Package: h2o / 2.2.5+dfsg2-3~bpo9+1

fix_CVE-2019_1.patch Patch series | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
Description: Fix HTTP/2 DoS attack vulnerabilities: CVE-2019-9512 CVE-2019-9514 CVE-2019-9515
From 743d6b6118c29b75d0b84ef7950a2721c32dfe3f Mon Sep 17 00:00:00 2001
From: Kazuho Oku <kazuhooku@gmail.com>
Date: Mon, 12 Aug 2019 21:40:04 +0900
Subject: [PATCH] Stop the read side when amount of unsent, non-flow-controlled
 data goes above 512KB.

---
 include/h2o/http2_internal.h |  4 ++--
 lib/http2/connection.c       | 25 +++++++++++++++++++++++--
 2 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/include/h2o/http2_internal.h b/include/h2o/http2_internal.h
index d919615c4..5cfc4d820 100644
--- a/include/h2o/http2_internal.h
+++ b/include/h2o/http2_internal.h
@@ -33,8 +33,8 @@
 typedef struct st_h2o_http2_conn_t h2o_http2_conn_t;
 typedef struct st_h2o_http2_stream_t h2o_http2_stream_t;
 
-/* connection flow control window + alpha */
-#define H2O_HTTP2_DEFAULT_OUTBUF_SIZE 81920
+#define H2O_HTTP2_DEFAULT_OUTBUF_SIZE 81920 /* the target size of each write call; connection flow control window + alpha */
+#define H2O_HTTP2_DEFAULT_OUTBUF_SOFT_MAX_SIZE 524288 /* 512KB; stops reading if size exceeds this value */
 
 /* hpack */
 
diff --git a/lib/http2/connection.c b/lib/http2/connection.c
index 2f8cad620..e2da29304 100644
--- a/lib/http2/connection.c
+++ b/lib/http2/connection.c
@@ -56,6 +56,7 @@ static const h2o_iovec_t SETTINGS_HOST_BIN = {H2O_STRLIT("\x00\x00\x0c"     /* f
 static __thread h2o_buffer_prototype_t wbuf_buffer_prototype = {{16}, {H2O_HTTP2_DEFAULT_OUTBUF_SIZE}};
 
 static void initiate_graceful_shutdown(h2o_context_t *ctx);
+static void close_connection_now(h2o_http2_conn_t *conn);
 static int close_connection(h2o_http2_conn_t *conn);
 static ssize_t expect_default(h2o_http2_conn_t *conn, const uint8_t *src, size_t len, const char **err_desc);
 static void do_emit_writereq(h2o_http2_conn_t *conn);
@@ -147,7 +148,12 @@ static void on_idle_timeout(h2o_timeout_entry_t *entry)
     h2o_http2_conn_t *conn = H2O_STRUCT_FROM_MEMBER(h2o_http2_conn_t, _timeout_entry, entry);
 
     enqueue_goaway(conn, H2O_HTTP2_ERROR_NONE, h2o_iovec_init(H2O_STRLIT("idle timeout")));
-    close_connection(conn);
+    if (conn->_write.buf_in_flight != NULL) {
+        close_connection_now(conn);
+    } else {
+        enqueue_goaway(conn, H2O_HTTP2_ERROR_NONE, h2o_iovec_init(H2O_STRLIT("idle timeout")));
+        close_connection(conn);
+    }
 }
 
 static void update_idle_timeout(h2o_http2_conn_t *conn)
@@ -247,7 +253,7 @@ void h2o_http2_conn_unregister_stream(h2o_http2_conn_t *conn, h2o_http2_stream_t
     }
 }
 
-static void close_connection_now(h2o_http2_conn_t *conn)
+void close_connection_now(h2o_http2_conn_t *conn)
 {
     h2o_http2_stream_t *stream;
 
@@ -937,10 +943,20 @@ static void on_upgrade_complete(void *_conn, h2o_socket_t *sock, size_t reqsize)
     }
 }
 
+static size_t bytes_in_buf(h2o_http2_conn_t *conn)
+{
+    size_t size = conn->_write.buf->size;
+    if (conn->_write.buf_in_flight != 0)
+        size += conn->_write.buf_in_flight->size;
+    return size;
+}
+
 void h2o_http2_conn_request_write(h2o_http2_conn_t *conn)
 {
     if (conn->state == H2O_HTTP2_CONN_STATE_IS_CLOSING)
         return;
+    if (h2o_socket_is_reading(conn->sock) && bytes_in_buf(conn) >= H2O_HTTP2_DEFAULT_OUTBUF_SOFT_MAX_SIZE)
+        h2o_socket_read_stop(conn->sock);
     request_gathered_write(conn);
 }
 
@@ -1001,6 +1017,11 @@ static void on_write_complete(h2o_socket_t *sock, const char *err)
     if (h2o_timeout_is_linked(&conn->_write.timeout_entry))
         h2o_timeout_unlink(&conn->_write.timeout_entry);
 
+    if (conn->state < H2O_HTTP2_CONN_STATE_IS_CLOSING) {
+        if (!h2o_socket_is_reading(conn->sock) && bytes_in_buf(conn) < H2O_HTTP2_DEFAULT_OUTBUF_SOFT_MAX_SIZE)
+            h2o_socket_read_start(conn->sock, on_read);
+    }
+
 #if !H2O_USE_LIBUV
     if (conn->state == H2O_HTTP2_CONN_STATE_OPEN) {
         if (conn->_write.buf->size != 0 || h2o_http2_scheduler_is_active(&conn->scheduler))