httpd: fix CVE-2019-9517 CVE-2019-10081 CVE-2019-10082 CVE-2020-1927 CVE-2020-1934
This commit is contained in:
parent
933f05e267
commit
c5a0493bc5
85
CVE-2019-9517_CVE-2019-10081_CVE-2019-10082-1.patch
Normal file
85
CVE-2019-9517_CVE-2019-10081_CVE-2019-10082-1.patch
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
From 2040a6943df462ef3fafd220043204ecd08f29dc Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jim Jagielski <jim@apache.org>
|
||||||
|
Date: Thu, 13 Jun 2019 11:08:29 +0000
|
||||||
|
Subject: [PATCH 1/5] Merge r1860260 from trunk:
|
||||||
|
|
||||||
|
* modules/http2: more copying of data to disentangle worker processing from main connection
|
||||||
|
|
||||||
|
Submitted by: icing
|
||||||
|
Reviewed by: icing, covener, jim
|
||||||
|
|
||||||
|
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1861247 13f79535-47bb-0310-9956-ffa450edef68
|
||||||
|
---
|
||||||
|
modules/http2/h2_headers.c | 11 +++++++++--
|
||||||
|
modules/http2/h2_headers.h | 8 +++++++-
|
||||||
|
modules/http2/h2_session.c | 1 +
|
||||||
|
3 files changed, 17 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/modules/http2/h2_headers.c b/modules/http2/h2_headers.c
|
||||||
|
index f01ab88..2be9545 100644
|
||||||
|
--- a/modules/http2/h2_headers.c
|
||||||
|
+++ b/modules/http2/h2_headers.c
|
||||||
|
@@ -101,8 +101,9 @@ apr_bucket *h2_bucket_headers_beam(struct h2_bucket_beam *beam,
|
||||||
|
const apr_bucket *src)
|
||||||
|
{
|
||||||
|
if (H2_BUCKET_IS_HEADERS(src)) {
|
||||||
|
- h2_headers *r = ((h2_bucket_headers *)src->data)->headers;
|
||||||
|
- apr_bucket *b = h2_bucket_headers_create(dest->bucket_alloc, r);
|
||||||
|
+ h2_headers *src_headers = ((h2_bucket_headers *)src->data)->headers;
|
||||||
|
+ apr_bucket *b = h2_bucket_headers_create(dest->bucket_alloc,
|
||||||
|
+ h2_headers_clone(dest->p, src_headers));
|
||||||
|
APR_BRIGADE_INSERT_TAIL(dest, b);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
@@ -153,6 +154,12 @@ h2_headers *h2_headers_copy(apr_pool_t *pool, h2_headers *h)
|
||||||
|
apr_table_copy(pool, h->notes), h->raw_bytes, pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
+h2_headers *h2_headers_clone(apr_pool_t *pool, h2_headers *h)
|
||||||
|
+{
|
||||||
|
+ return h2_headers_create(h->status, apr_table_clone(pool, h->headers),
|
||||||
|
+ apr_table_clone(pool, h->notes), h->raw_bytes, pool);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
h2_headers *h2_headers_die(apr_status_t type,
|
||||||
|
const h2_request *req, apr_pool_t *pool)
|
||||||
|
{
|
||||||
|
diff --git a/modules/http2/h2_headers.h b/modules/http2/h2_headers.h
|
||||||
|
index 840e8c4..b7d95a1 100644
|
||||||
|
--- a/modules/http2/h2_headers.h
|
||||||
|
+++ b/modules/http2/h2_headers.h
|
||||||
|
@@ -59,12 +59,18 @@ h2_headers *h2_headers_rcreate(request_rec *r, int status,
|
||||||
|
apr_table_t *header, apr_pool_t *pool);
|
||||||
|
|
||||||
|
/**
|
||||||
|
- * Clone the headers into another pool. This will not copy any
|
||||||
|
+ * Copy the headers into another pool. This will not copy any
|
||||||
|
* header strings.
|
||||||
|
*/
|
||||||
|
h2_headers *h2_headers_copy(apr_pool_t *pool, h2_headers *h);
|
||||||
|
|
||||||
|
/**
|
||||||
|
+ * Clone the headers into another pool. This will also clone any
|
||||||
|
+ * header strings.
|
||||||
|
+ */
|
||||||
|
+h2_headers *h2_headers_clone(apr_pool_t *pool, h2_headers *h);
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
* Create the headers for the given error.
|
||||||
|
* @param stream_id id of the stream to create the headers for
|
||||||
|
* @param type the error code
|
||||||
|
diff --git a/modules/http2/h2_session.c b/modules/http2/h2_session.c
|
||||||
|
index a1b31d2..3f0e9c9 100644
|
||||||
|
--- a/modules/http2/h2_session.c
|
||||||
|
+++ b/modules/http2/h2_session.c
|
||||||
|
@@ -1950,6 +1950,7 @@ static void on_stream_state_enter(void *ctx, h2_stream *stream)
|
||||||
|
ev_stream_closed(session, stream);
|
||||||
|
break;
|
||||||
|
case H2_SS_CLEANUP:
|
||||||
|
+ nghttp2_session_set_stream_user_data(session->ngh2, stream->id, NULL);
|
||||||
|
h2_mplx_stream_cleanup(session->mplx, stream);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
--
|
||||||
|
1.8.3.1
|
||||||
|
|
||||||
121
CVE-2019-9517_CVE-2019-10081_CVE-2019-10082-2.patch
Normal file
121
CVE-2019-9517_CVE-2019-10081_CVE-2019-10082-2.patch
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
From 04f21f8422dd763da2f09badac965ff03e59aca8 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jim Jagielski <jim@apache.org>
|
||||||
|
Date: Thu, 13 Jun 2019 11:09:12 +0000
|
||||||
|
Subject: [PATCH 2/5] Merge r1707084, r1707093, r1707159, r1707362 from trunk:
|
||||||
|
|
||||||
|
eor_bucket: don't destroy the request multiple times should any filter
|
||||||
|
do a copy (e.g. mod_bucketeer).
|
||||||
|
|
||||||
|
eor_bucket: follow up to r1707084: fix comment.
|
||||||
|
|
||||||
|
eor_bucket: follow up to r1707084: use an inner shared bucket.
|
||||||
|
|
||||||
|
eor_bucket: follow up to r1707159.
|
||||||
|
We need an apr_bucket_refcount, as spotted by Ruediger.
|
||||||
|
Submitted by: ylavic
|
||||||
|
Reviewed by: icing, covener, jim
|
||||||
|
|
||||||
|
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1861248 13f79535-47bb-0310-9956-ffa450edef68
|
||||||
|
---
|
||||||
|
server/eor_bucket.c | 43 ++++++++++++++++++++++++++++---------------
|
||||||
|
1 file changed, 28 insertions(+), 15 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/server/eor_bucket.c b/server/eor_bucket.c
|
||||||
|
index 4d3e1ec..ecb809c 100644
|
||||||
|
--- a/server/eor_bucket.c
|
||||||
|
+++ b/server/eor_bucket.c
|
||||||
|
@@ -19,17 +19,22 @@
|
||||||
|
#include "http_protocol.h"
|
||||||
|
#include "scoreboard.h"
|
||||||
|
|
||||||
|
+typedef struct {
|
||||||
|
+ apr_bucket_refcount refcount;
|
||||||
|
+ request_rec *data;
|
||||||
|
+} ap_bucket_eor;
|
||||||
|
+
|
||||||
|
static apr_status_t eor_bucket_cleanup(void *data)
|
||||||
|
{
|
||||||
|
- apr_bucket *b = (apr_bucket *)data;
|
||||||
|
- request_rec *r = (request_rec *)b->data;
|
||||||
|
+ request_rec **rp = data;
|
||||||
|
|
||||||
|
- if (r != NULL) {
|
||||||
|
+ if (*rp) {
|
||||||
|
+ request_rec *r = *rp;
|
||||||
|
/*
|
||||||
|
* If eor_bucket_destroy is called after us, this prevents
|
||||||
|
* eor_bucket_destroy from trying to destroy the pool again.
|
||||||
|
*/
|
||||||
|
- b->data = NULL;
|
||||||
|
+ *rp = NULL;
|
||||||
|
/* Update child status and log the transaction */
|
||||||
|
ap_update_child_status(r->connection->sbh, SERVER_BUSY_LOG, r);
|
||||||
|
ap_run_log_transaction(r);
|
||||||
|
@@ -50,11 +55,13 @@ static apr_status_t eor_bucket_read(apr_bucket *b, const char **str,
|
||||||
|
|
||||||
|
AP_DECLARE(apr_bucket *) ap_bucket_eor_make(apr_bucket *b, request_rec *r)
|
||||||
|
{
|
||||||
|
- b->length = 0;
|
||||||
|
- b->start = 0;
|
||||||
|
- b->data = r;
|
||||||
|
- b->type = &ap_bucket_type_eor;
|
||||||
|
+ ap_bucket_eor *h;
|
||||||
|
+
|
||||||
|
+ h = apr_bucket_alloc(sizeof(*h), b->list);
|
||||||
|
+ h->data = r;
|
||||||
|
|
||||||
|
+ b = apr_bucket_shared_make(b, h, 0, 0);
|
||||||
|
+ b->type = &ap_bucket_type_eor;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -66,7 +73,9 @@ AP_DECLARE(apr_bucket *) ap_bucket_eor_create(apr_bucket_alloc_t *list,
|
||||||
|
APR_BUCKET_INIT(b);
|
||||||
|
b->free = apr_bucket_free;
|
||||||
|
b->list = list;
|
||||||
|
+ b = ap_bucket_eor_make(b, r);
|
||||||
|
if (r) {
|
||||||
|
+ ap_bucket_eor *h = b->data;
|
||||||
|
/*
|
||||||
|
* Register a cleanup for the request pool as the eor bucket could
|
||||||
|
* have been allocated from a different pool then the request pool
|
||||||
|
@@ -76,18 +85,22 @@ AP_DECLARE(apr_bucket *) ap_bucket_eor_create(apr_bucket_alloc_t *list,
|
||||||
|
* We need to use a pre-cleanup here because a module may create a
|
||||||
|
* sub-pool which is still needed during the log_transaction hook.
|
||||||
|
*/
|
||||||
|
- apr_pool_pre_cleanup_register(r->pool, (void *)b, eor_bucket_cleanup);
|
||||||
|
+ apr_pool_pre_cleanup_register(r->pool, &h->data, eor_bucket_cleanup);
|
||||||
|
}
|
||||||
|
- return ap_bucket_eor_make(b, r);
|
||||||
|
+ return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void eor_bucket_destroy(void *data)
|
||||||
|
{
|
||||||
|
- request_rec *r = (request_rec *)data;
|
||||||
|
+ ap_bucket_eor *h = data;
|
||||||
|
|
||||||
|
- if (r) {
|
||||||
|
- /* eor_bucket_cleanup will be called when the pool gets destroyed */
|
||||||
|
- apr_pool_destroy(r->pool);
|
||||||
|
+ if (apr_bucket_shared_destroy(h)) {
|
||||||
|
+ request_rec *r = h->data;
|
||||||
|
+ if (r) {
|
||||||
|
+ /* eor_bucket_cleanup will be called when the pool gets destroyed */
|
||||||
|
+ apr_pool_destroy(r->pool);
|
||||||
|
+ }
|
||||||
|
+ apr_bucket_free(h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -97,6 +110,6 @@ AP_DECLARE_DATA const apr_bucket_type_t ap_bucket_type_eor = {
|
||||||
|
eor_bucket_read,
|
||||||
|
apr_bucket_setaside_noop,
|
||||||
|
apr_bucket_split_notimpl,
|
||||||
|
- apr_bucket_simple_copy
|
||||||
|
+ apr_bucket_shared_copy
|
||||||
|
};
|
||||||
|
|
||||||
|
--
|
||||||
|
1.8.3.1
|
||||||
|
|
||||||
306
CVE-2019-9517_CVE-2019-10081_CVE-2019-10082-3.patch
Normal file
306
CVE-2019-9517_CVE-2019-10081_CVE-2019-10082-3.patch
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
From 1125fc2240353c41db09eac8fedcc75dfdf44edb Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jim Jagielski <jim@apache.org>
|
||||||
|
Date: Wed, 19 Sep 2018 12:55:26 +0000
|
||||||
|
Subject: [PATCH 3/5] Merge r1835118 from trunk:
|
||||||
|
|
||||||
|
On the trunk:
|
||||||
|
|
||||||
|
* silencing gcc uninitialized warning
|
||||||
|
* refrainning from apr_table_addn() use since pool debug assumptions are in conflict
|
||||||
|
* adding more assertions
|
||||||
|
* copy-porting changes to base64 encoding code from mod_md
|
||||||
|
|
||||||
|
Submitted by: icing
|
||||||
|
Reviewed by: icing, minfrin, jim
|
||||||
|
|
||||||
|
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1841330 13f79535-47bb-0310-9956-ffa450edef68
|
||||||
|
---
|
||||||
|
modules/http2/h2_bucket_beam.c | 2 +-
|
||||||
|
modules/http2/h2_from_h1.c | 4 +-
|
||||||
|
modules/http2/h2_h2.c | 2 +-
|
||||||
|
modules/http2/h2_headers.c | 7 ++--
|
||||||
|
modules/http2/h2_mplx.c | 4 ++
|
||||||
|
modules/http2/h2_proxy_session.c | 4 +-
|
||||||
|
modules/http2/h2_util.c | 86 +++++++++++++++++++++-------------------
|
||||||
|
7 files changed, 58 insertions(+), 51 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/modules/http2/h2_bucket_beam.c b/modules/http2/h2_bucket_beam.c
|
||||||
|
index 9f6fa82..f79cbe3 100644
|
||||||
|
--- a/modules/http2/h2_bucket_beam.c
|
||||||
|
+++ b/modules/http2/h2_bucket_beam.c
|
||||||
|
@@ -775,7 +775,7 @@ static apr_status_t append_bucket(h2_bucket_beam *beam,
|
||||||
|
const char *data;
|
||||||
|
apr_size_t len;
|
||||||
|
apr_status_t status;
|
||||||
|
- int can_beam, check_len;
|
||||||
|
+ int can_beam = 0, check_len;
|
||||||
|
|
||||||
|
if (beam->aborted) {
|
||||||
|
return APR_ECONNABORTED;
|
||||||
|
diff --git a/modules/http2/h2_from_h1.c b/modules/http2/h2_from_h1.c
|
||||||
|
index ae264a9..dd6ad90 100644
|
||||||
|
--- a/modules/http2/h2_from_h1.c
|
||||||
|
+++ b/modules/http2/h2_from_h1.c
|
||||||
|
@@ -164,7 +164,7 @@ static int copy_header(void *ctx, const char *name, const char *value)
|
||||||
|
{
|
||||||
|
apr_table_t *headers = ctx;
|
||||||
|
|
||||||
|
- apr_table_addn(headers, name, value);
|
||||||
|
+ apr_table_add(headers, name, value);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -250,7 +250,7 @@ static h2_headers *create_response(h2_task *task, request_rec *r)
|
||||||
|
if (r->no_cache && !apr_table_get(r->headers_out, "Expires")) {
|
||||||
|
char *date = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
|
||||||
|
ap_recent_rfc822_date(date, r->request_time);
|
||||||
|
- apr_table_addn(r->headers_out, "Expires", date);
|
||||||
|
+ apr_table_add(r->headers_out, "Expires", date);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is a hack, but I can't find anyway around it. The idea is that
|
||||||
|
diff --git a/modules/http2/h2_h2.c b/modules/http2/h2_h2.c
|
||||||
|
index dfee6b5..5580cef 100644
|
||||||
|
--- a/modules/http2/h2_h2.c
|
||||||
|
+++ b/modules/http2/h2_h2.c
|
||||||
|
@@ -694,7 +694,7 @@ static void check_push(request_rec *r, const char *tag)
|
||||||
|
tag, conf->push_list->nelts);
|
||||||
|
for (i = 0; i < conf->push_list->nelts; ++i) {
|
||||||
|
h2_push_res *push = &APR_ARRAY_IDX(conf->push_list, i, h2_push_res);
|
||||||
|
- apr_table_addn(r->headers_out, "Link",
|
||||||
|
+ apr_table_add(r->headers_out, "Link",
|
||||||
|
apr_psprintf(r->pool, "<%s>; rel=preload%s",
|
||||||
|
push->uri_ref, push->critical? "; critical" : ""));
|
||||||
|
}
|
||||||
|
diff --git a/modules/http2/h2_headers.c b/modules/http2/h2_headers.c
|
||||||
|
index 2be9545..49d9c0a 100644
|
||||||
|
--- a/modules/http2/h2_headers.c
|
||||||
|
+++ b/modules/http2/h2_headers.c
|
||||||
|
@@ -117,9 +117,9 @@ h2_headers *h2_headers_create(int status, apr_table_t *headers_in,
|
||||||
|
{
|
||||||
|
h2_headers *headers = apr_pcalloc(pool, sizeof(h2_headers));
|
||||||
|
headers->status = status;
|
||||||
|
- headers->headers = (headers_in? apr_table_copy(pool, headers_in)
|
||||||
|
+ headers->headers = (headers_in? apr_table_clone(pool, headers_in)
|
||||||
|
: apr_table_make(pool, 5));
|
||||||
|
- headers->notes = (notes? apr_table_copy(pool, notes)
|
||||||
|
+ headers->notes = (notes? apr_table_clone(pool, notes)
|
||||||
|
: apr_table_make(pool, 5));
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
@@ -150,8 +150,7 @@ h2_headers *h2_headers_rcreate(request_rec *r, int status,
|
||||||
|
|
||||||
|
h2_headers *h2_headers_copy(apr_pool_t *pool, h2_headers *h)
|
||||||
|
{
|
||||||
|
- return h2_headers_create(h->status, apr_table_copy(pool, h->headers),
|
||||||
|
- apr_table_copy(pool, h->notes), h->raw_bytes, pool);
|
||||||
|
+ return h2_headers_create(h->status, h->headers, h->notes, h->raw_bytes, pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
h2_headers *h2_headers_clone(apr_pool_t *pool, h2_headers *h)
|
||||||
|
diff --git a/modules/http2/h2_mplx.c b/modules/http2/h2_mplx.c
|
||||||
|
index 29f040c..db3cb63 100644
|
||||||
|
--- a/modules/http2/h2_mplx.c
|
||||||
|
+++ b/modules/http2/h2_mplx.c
|
||||||
|
@@ -476,6 +476,7 @@ void h2_mplx_release_and_join(h2_mplx *m, apr_thread_cond_t *wait)
|
||||||
|
h2_ihash_iter(m->shold, report_stream_iter, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ ap_assert(m->tasks_active == 0);
|
||||||
|
m->join_wait = NULL;
|
||||||
|
|
||||||
|
/* 4. close the h2_req_enginge shed */
|
||||||
|
@@ -765,6 +766,9 @@ apr_status_t h2_mplx_pop_task(h2_mplx *m, h2_task **ptask)
|
||||||
|
apr_status_t rv = APR_EOF;
|
||||||
|
|
||||||
|
*ptask = NULL;
|
||||||
|
+ ap_assert(m);
|
||||||
|
+ ap_assert(m->lock);
|
||||||
|
+
|
||||||
|
if (APR_SUCCESS != (rv = apr_thread_mutex_lock(m->lock))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
diff --git a/modules/http2/h2_proxy_session.c b/modules/http2/h2_proxy_session.c
|
||||||
|
index a077ce1..8389c7c 100644
|
||||||
|
--- a/modules/http2/h2_proxy_session.c
|
||||||
|
+++ b/modules/http2/h2_proxy_session.c
|
||||||
|
@@ -237,7 +237,7 @@ static int before_frame_send(nghttp2_session *ngh2,
|
||||||
|
|
||||||
|
static int add_header(void *table, const char *n, const char *v)
|
||||||
|
{
|
||||||
|
- apr_table_addn(table, n, v);
|
||||||
|
+ apr_table_add(table, n, v);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -361,7 +361,7 @@ static void h2_proxy_stream_end_headers_out(h2_proxy_stream *stream)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create a "Via:" response header entry and merge it */
|
||||||
|
- apr_table_addn(r->headers_out, "Via",
|
||||||
|
+ apr_table_add(r->headers_out, "Via",
|
||||||
|
(session->conf->viaopt == via_full)
|
||||||
|
? apr_psprintf(p, "%d.%d %s%s (%s)",
|
||||||
|
HTTP_VERSION_MAJOR(r->proto_num),
|
||||||
|
diff --git a/modules/http2/h2_util.c b/modules/http2/h2_util.c
|
||||||
|
index 3d7ba37..9dacd8b 100644
|
||||||
|
--- a/modules/http2/h2_util.c
|
||||||
|
+++ b/modules/http2/h2_util.c
|
||||||
|
@@ -115,26 +115,28 @@ void h2_util_camel_case_header(char *s, size_t len)
|
||||||
|
|
||||||
|
/* base64 url encoding ****************************************************************************/
|
||||||
|
|
||||||
|
-static const int BASE64URL_UINT6[] = {
|
||||||
|
+#define N6 (unsigned int)-1
|
||||||
|
+
|
||||||
|
+static const unsigned int BASE64URL_UINT6[] = {
|
||||||
|
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
||||||
|
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0 */
|
||||||
|
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 1 */
|
||||||
|
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, /* 2 */
|
||||||
|
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 3 */
|
||||||
|
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 4 */
|
||||||
|
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, /* 5 */
|
||||||
|
- -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 6 */
|
||||||
|
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 7 */
|
||||||
|
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 8 */
|
||||||
|
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 9 */
|
||||||
|
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a */
|
||||||
|
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* b */
|
||||||
|
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* c */
|
||||||
|
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* d */
|
||||||
|
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* e */
|
||||||
|
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* f */
|
||||||
|
+ N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* 0 */
|
||||||
|
+ N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* 1 */
|
||||||
|
+ N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, 62, N6, N6, /* 2 */
|
||||||
|
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, N6, N6, N6, N6, N6, N6, /* 3 */
|
||||||
|
+ N6, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 4 */
|
||||||
|
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, N6, N6, N6, N6, 63, /* 5 */
|
||||||
|
+ N6, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 6 */
|
||||||
|
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, N6, N6, N6, N6, N6, /* 7 */
|
||||||
|
+ N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* 8 */
|
||||||
|
+ N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* 9 */
|
||||||
|
+ N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* a */
|
||||||
|
+ N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* b */
|
||||||
|
+ N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* c */
|
||||||
|
+ N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* d */
|
||||||
|
+ N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* e */
|
||||||
|
+ N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6 /* f */
|
||||||
|
};
|
||||||
|
-static const char BASE64URL_CHARS[] = {
|
||||||
|
+static const unsigned char BASE64URL_CHARS[] = {
|
||||||
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 0 - 9 */
|
||||||
|
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 10 - 19 */
|
||||||
|
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', /* 20 - 29 */
|
||||||
|
@@ -144,21 +146,23 @@ static const char BASE64URL_CHARS[] = {
|
||||||
|
'8', '9', '-', '_', ' ', ' ', ' ', ' ', ' ', ' ', /* 60 - 69 */
|
||||||
|
};
|
||||||
|
|
||||||
|
+#define BASE64URL_CHAR(x) BASE64URL_CHARS[ (unsigned int)(x) & 0x3fu ]
|
||||||
|
+
|
||||||
|
apr_size_t h2_util_base64url_decode(const char **decoded, const char *encoded,
|
||||||
|
apr_pool_t *pool)
|
||||||
|
{
|
||||||
|
const unsigned char *e = (const unsigned char *)encoded;
|
||||||
|
const unsigned char *p = e;
|
||||||
|
unsigned char *d;
|
||||||
|
- int n;
|
||||||
|
- apr_size_t len, mlen, remain, i;
|
||||||
|
+ unsigned int n;
|
||||||
|
+ long len, mlen, remain, i;
|
||||||
|
|
||||||
|
- while (*p && BASE64URL_UINT6[ *p ] != -1) {
|
||||||
|
+ while (*p && BASE64URL_UINT6[ *p ] != N6) {
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
- len = p - e;
|
||||||
|
+ len = (int)(p - e);
|
||||||
|
mlen = (len/4)*4;
|
||||||
|
- *decoded = apr_pcalloc(pool, len+1);
|
||||||
|
+ *decoded = apr_pcalloc(pool, (apr_size_t)len + 1);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
d = (unsigned char*)*decoded;
|
||||||
|
@@ -167,60 +171,60 @@ apr_size_t h2_util_base64url_decode(const char **decoded, const char *encoded,
|
||||||
|
(BASE64URL_UINT6[ e[i+1] ] << 12) +
|
||||||
|
(BASE64URL_UINT6[ e[i+2] ] << 6) +
|
||||||
|
(BASE64URL_UINT6[ e[i+3] ]));
|
||||||
|
- *d++ = n >> 16;
|
||||||
|
- *d++ = n >> 8 & 0xffu;
|
||||||
|
- *d++ = n & 0xffu;
|
||||||
|
+ *d++ = (unsigned char)(n >> 16);
|
||||||
|
+ *d++ = (unsigned char)(n >> 8 & 0xffu);
|
||||||
|
+ *d++ = (unsigned char)(n & 0xffu);
|
||||||
|
}
|
||||||
|
remain = len - mlen;
|
||||||
|
switch (remain) {
|
||||||
|
case 2:
|
||||||
|
n = ((BASE64URL_UINT6[ e[mlen+0] ] << 18) +
|
||||||
|
(BASE64URL_UINT6[ e[mlen+1] ] << 12));
|
||||||
|
- *d++ = n >> 16;
|
||||||
|
+ *d++ = (unsigned char)(n >> 16);
|
||||||
|
remain = 1;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
n = ((BASE64URL_UINT6[ e[mlen+0] ] << 18) +
|
||||||
|
(BASE64URL_UINT6[ e[mlen+1] ] << 12) +
|
||||||
|
(BASE64URL_UINT6[ e[mlen+2] ] << 6));
|
||||||
|
- *d++ = n >> 16;
|
||||||
|
- *d++ = n >> 8 & 0xffu;
|
||||||
|
+ *d++ = (unsigned char)(n >> 16);
|
||||||
|
+ *d++ = (unsigned char)(n >> 8 & 0xffu);
|
||||||
|
remain = 2;
|
||||||
|
break;
|
||||||
|
default: /* do nothing */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
- return mlen/4*3 + remain;
|
||||||
|
+ return (apr_size_t)(mlen/4*3 + remain);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *h2_util_base64url_encode(const char *data,
|
||||||
|
apr_size_t dlen, apr_pool_t *pool)
|
||||||
|
{
|
||||||
|
- long i, len = (int)dlen;
|
||||||
|
+ int i, len = (int)dlen;
|
||||||
|
apr_size_t slen = ((dlen+2)/3)*4 + 1; /* 0 terminated */
|
||||||
|
const unsigned char *udata = (const unsigned char*)data;
|
||||||
|
- char *enc, *p = apr_pcalloc(pool, slen);
|
||||||
|
+ unsigned char *enc, *p = apr_pcalloc(pool, slen);
|
||||||
|
|
||||||
|
enc = p;
|
||||||
|
for (i = 0; i < len-2; i+= 3) {
|
||||||
|
- *p++ = BASE64URL_CHARS[ (udata[i] >> 2) & 0x3fu ];
|
||||||
|
- *p++ = BASE64URL_CHARS[ ((udata[i] << 4) + (udata[i+1] >> 4)) & 0x3fu ];
|
||||||
|
- *p++ = BASE64URL_CHARS[ ((udata[i+1] << 2) + (udata[i+2] >> 6)) & 0x3fu ];
|
||||||
|
- *p++ = BASE64URL_CHARS[ udata[i+2] & 0x3fu ];
|
||||||
|
+ *p++ = BASE64URL_CHAR( (udata[i] >> 2) );
|
||||||
|
+ *p++ = BASE64URL_CHAR( (udata[i] << 4) + (udata[i+1] >> 4) );
|
||||||
|
+ *p++ = BASE64URL_CHAR( (udata[i+1] << 2) + (udata[i+2] >> 6) );
|
||||||
|
+ *p++ = BASE64URL_CHAR( (udata[i+2]) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < len) {
|
||||||
|
- *p++ = BASE64URL_CHARS[ (udata[i] >> 2) & 0x3fu ];
|
||||||
|
+ *p++ = BASE64URL_CHAR( (udata[i] >> 2) );
|
||||||
|
if (i == (len - 1)) {
|
||||||
|
- *p++ = BASE64URL_CHARS[ (udata[i] << 4) & 0x3fu ];
|
||||||
|
+ *p++ = BASE64URL_CHARS[ ((unsigned int)udata[i] << 4) & 0x3fu ];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
- *p++ = BASE64URL_CHARS[ ((udata[i] << 4) + (udata[i+1] >> 4)) & 0x3fu ];
|
||||||
|
- *p++ = BASE64URL_CHARS[ (udata[i+1] << 2) & 0x3fu ];
|
||||||
|
+ *p++ = BASE64URL_CHAR( (udata[i] << 4) + (udata[i+1] >> 4) );
|
||||||
|
+ *p++ = BASE64URL_CHAR( (udata[i+1] << 2) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*p++ = '\0';
|
||||||
|
- return enc;
|
||||||
|
+ return (char *)enc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
--
|
||||||
|
1.8.3.1
|
||||||
|
|
||||||
4406
CVE-2019-9517_CVE-2019-10081_CVE-2019-10082-4.patch
Normal file
4406
CVE-2019-9517_CVE-2019-10081_CVE-2019-10082-4.patch
Normal file
File diff suppressed because it is too large
Load Diff
860
CVE-2019-9517_CVE-2019-10081_CVE-2019-10082-5.patch
Normal file
860
CVE-2019-9517_CVE-2019-10081_CVE-2019-10082-5.patch
Normal file
@ -0,0 +1,860 @@
|
|||||||
|
From 94de05dacf17a60a8c3b34b5ded37fc4dc04709b Mon Sep 17 00:00:00 2001
|
||||||
|
From: Stefan Eissing <icing@apache.org>
|
||||||
|
Date: Thu, 1 Aug 2019 08:18:03 +0000
|
||||||
|
Subject: [PATCH 5/5] Merge of r1861338,1862475,1862583,1862865,1863221,1863276
|
||||||
|
from trunk:
|
||||||
|
|
||||||
|
*) mod_http2: core setting "LimitRequestFieldSize" is not additionally checked on
|
||||||
|
merged header fields, just as HTTP/1.1 does. [Stefan Eissing, Michael Kaufmann]
|
||||||
|
|
||||||
|
*) mod_http2: fixed a bug that prevented proper stream cleanup when connection
|
||||||
|
throttling was in place. Stream resets by clients on streams initiated by them
|
||||||
|
are counted as possible trigger for throttling. [Stefan Eissing]
|
||||||
|
|
||||||
|
*) mod_http2/mpm_event: Fixes the behaviour when a HTTP/2 connection has nothing
|
||||||
|
more to write with streams ongoing (flow control block). The timeout waiting
|
||||||
|
for the client to send WINODW_UPDATE was incorrectly KeepAliveTimeout and not
|
||||||
|
Timeout as it should be. Fixes PR 63534. [Yann Ylavic, Stefan Eissing]
|
||||||
|
|
||||||
|
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1864126 13f79535-47bb-0310-9956-ffa450edef68
|
||||||
|
---
|
||||||
|
modules/http2/h2_conn.c | 7 ++
|
||||||
|
modules/http2/h2_filter.c | 52 +++++++++-
|
||||||
|
modules/http2/h2_mplx.c | 249 +++++++++++++++++++++++++++------------------
|
||||||
|
modules/http2/h2_mplx.h | 11 +-
|
||||||
|
modules/http2/h2_session.c | 19 +++-
|
||||||
|
modules/http2/h2_stream.c | 80 +++++++++++----
|
||||||
|
modules/http2/h2_stream.h | 4 +
|
||||||
|
modules/http2/h2_task.c | 8 +-
|
||||||
|
modules/http2/h2_task.h | 2 +
|
||||||
|
server/mpm/event/event.c | 7 +-
|
||||||
|
10 files changed, 304 insertions(+), 135 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/modules/http2/h2_conn.c b/modules/http2/h2_conn.c
|
||||||
|
index 9ef0ea0..0b78a84 100644
|
||||||
|
--- a/modules/http2/h2_conn.c
|
||||||
|
+++ b/modules/http2/h2_conn.c
|
||||||
|
@@ -231,6 +231,13 @@ apr_status_t h2_conn_run(conn_rec *c)
|
||||||
|
case H2_SESSION_ST_BUSY:
|
||||||
|
case H2_SESSION_ST_WAIT:
|
||||||
|
c->cs->state = CONN_STATE_WRITE_COMPLETION;
|
||||||
|
+ if (c->cs && (session->open_streams || !session->remote.emitted_count)) {
|
||||||
|
+ /* let the MPM know that we are not done and want
|
||||||
|
+ * the Timeout behaviour instead of a KeepAliveTimeout
|
||||||
|
+ * See PR 63534.
|
||||||
|
+ */
|
||||||
|
+ c->cs->sense = CONN_SENSE_WANT_READ;
|
||||||
|
+ }
|
||||||
|
break;
|
||||||
|
case H2_SESSION_ST_CLEANUP:
|
||||||
|
case H2_SESSION_ST_DONE:
|
||||||
|
diff --git a/modules/http2/h2_filter.c b/modules/http2/h2_filter.c
|
||||||
|
index 5fd237f..2fc5e12 100644
|
||||||
|
--- a/modules/http2/h2_filter.c
|
||||||
|
+++ b/modules/http2/h2_filter.c
|
||||||
|
@@ -493,6 +493,52 @@ static apr_status_t status_event(void *ctx, h2_bucket_event event,
|
||||||
|
return APR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static apr_status_t discard_body(request_rec *r, apr_off_t maxlen)
|
||||||
|
+{
|
||||||
|
+ apr_bucket_brigade *bb;
|
||||||
|
+ int seen_eos;
|
||||||
|
+ apr_status_t rv;
|
||||||
|
+
|
||||||
|
+ bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
|
||||||
|
+ seen_eos = 0;
|
||||||
|
+ do {
|
||||||
|
+ apr_bucket *bucket;
|
||||||
|
+
|
||||||
|
+ rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
|
||||||
|
+ APR_BLOCK_READ, HUGE_STRING_LEN);
|
||||||
|
+
|
||||||
|
+ if (rv != APR_SUCCESS) {
|
||||||
|
+ apr_brigade_destroy(bb);
|
||||||
|
+ return rv;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (bucket = APR_BRIGADE_FIRST(bb);
|
||||||
|
+ bucket != APR_BRIGADE_SENTINEL(bb);
|
||||||
|
+ bucket = APR_BUCKET_NEXT(bucket))
|
||||||
|
+ {
|
||||||
|
+ const char *data;
|
||||||
|
+ apr_size_t len;
|
||||||
|
+
|
||||||
|
+ if (APR_BUCKET_IS_EOS(bucket)) {
|
||||||
|
+ seen_eos = 1;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ if (bucket->length == 0) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
|
||||||
|
+ if (rv != APR_SUCCESS) {
|
||||||
|
+ apr_brigade_destroy(bb);
|
||||||
|
+ return rv;
|
||||||
|
+ }
|
||||||
|
+ maxlen -= bucket->length;
|
||||||
|
+ }
|
||||||
|
+ apr_brigade_cleanup(bb);
|
||||||
|
+ } while (!seen_eos && maxlen >= 0);
|
||||||
|
+
|
||||||
|
+ return APR_SUCCESS;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
int h2_filter_h2_status_handler(request_rec *r)
|
||||||
|
{
|
||||||
|
conn_rec *c = r->connection;
|
||||||
|
@@ -510,8 +556,10 @@ int h2_filter_h2_status_handler(request_rec *r)
|
||||||
|
|
||||||
|
task = h2_ctx_get_task(r->connection);
|
||||||
|
if (task) {
|
||||||
|
-
|
||||||
|
- if ((status = ap_discard_request_body(r)) != OK) {
|
||||||
|
+ /* In this handler, we do some special sauce to send footers back,
|
||||||
|
+ * IFF we received footers in the request. This is used in our test
|
||||||
|
+ * cases, since CGI has no way of handling those. */
|
||||||
|
+ if ((status = discard_body(r, 1024)) != OK) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/modules/http2/h2_mplx.c b/modules/http2/h2_mplx.c
|
||||||
|
index fae77c7..9b504a5 100644
|
||||||
|
--- a/modules/http2/h2_mplx.c
|
||||||
|
+++ b/modules/http2/h2_mplx.c
|
||||||
|
@@ -53,8 +53,12 @@ typedef struct {
|
||||||
|
h2_mplx *m;
|
||||||
|
h2_stream *stream;
|
||||||
|
apr_time_t now;
|
||||||
|
+ apr_size_t count;
|
||||||
|
} stream_iter_ctx;
|
||||||
|
|
||||||
|
+static apr_status_t mplx_be_happy(h2_mplx *m);
|
||||||
|
+static apr_status_t mplx_be_annoyed(h2_mplx *m);
|
||||||
|
+
|
||||||
|
apr_status_t h2_mplx_child_init(apr_pool_t *pool, server_rec *s)
|
||||||
|
{
|
||||||
|
return APR_SUCCESS;
|
||||||
|
@@ -98,7 +102,7 @@ static void stream_input_consumed(void *ctx, h2_bucket_beam *beam, apr_off_t len
|
||||||
|
|
||||||
|
static void stream_joined(h2_mplx *m, h2_stream *stream)
|
||||||
|
{
|
||||||
|
- ap_assert(!stream->task || stream->task->worker_done);
|
||||||
|
+ ap_assert(!h2_task_has_started(stream->task) || stream->task->worker_done);
|
||||||
|
|
||||||
|
h2_ihash_remove(m->shold, stream->id);
|
||||||
|
h2_ihash_add(m->spurge, stream);
|
||||||
|
@@ -124,7 +128,7 @@ static void stream_cleanup(h2_mplx *m, h2_stream *stream)
|
||||||
|
h2_ififo_remove(m->readyq, stream->id);
|
||||||
|
h2_ihash_add(m->shold, stream);
|
||||||
|
|
||||||
|
- if (!stream->task || stream->task->worker_done) {
|
||||||
|
+ if (!h2_task_has_started(stream->task) || stream->task->done_done) {
|
||||||
|
stream_joined(m, stream);
|
||||||
|
}
|
||||||
|
else if (stream->task) {
|
||||||
|
@@ -194,7 +198,6 @@ h2_mplx *h2_mplx_create(conn_rec *c, server_rec *s, apr_pool_t *parent,
|
||||||
|
m->stream_max_mem = h2_config_sgeti(s, H2_CONF_STREAM_MAX_MEM);
|
||||||
|
|
||||||
|
m->streams = h2_ihash_create(m->pool, offsetof(h2_stream,id));
|
||||||
|
- m->sredo = h2_ihash_create(m->pool, offsetof(h2_stream,id));
|
||||||
|
m->shold = h2_ihash_create(m->pool, offsetof(h2_stream,id));
|
||||||
|
m->spurge = h2_ihash_create(m->pool, offsetof(h2_stream,id));
|
||||||
|
m->q = h2_iq_create(m->pool, m->max_streams);
|
||||||
|
@@ -208,8 +211,8 @@ h2_mplx *h2_mplx_create(conn_rec *c, server_rec *s, apr_pool_t *parent,
|
||||||
|
m->workers = workers;
|
||||||
|
m->max_active = workers->max_workers;
|
||||||
|
m->limit_active = 6; /* the original h1 max parallel connections */
|
||||||
|
- m->last_limit_change = m->last_idle_block = apr_time_now();
|
||||||
|
- m->limit_change_interval = apr_time_from_msec(100);
|
||||||
|
+ m->last_mood_change = apr_time_now();
|
||||||
|
+ m->mood_update_interval = apr_time_from_msec(100);
|
||||||
|
|
||||||
|
m->spare_slaves = apr_array_make(m->pool, 10, sizeof(conn_rec*));
|
||||||
|
}
|
||||||
|
@@ -431,6 +434,10 @@ void h2_mplx_release_and_join(h2_mplx *m, apr_thread_cond_t *wait)
|
||||||
|
|
||||||
|
/* How to shut down a h2 connection:
|
||||||
|
* 1. cancel all streams still active */
|
||||||
|
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
|
||||||
|
+ "h2_mplx(%ld): release, %d/%d/%d streams (total/hold/purge), %d active tasks",
|
||||||
|
+ m->id, (int)h2_ihash_count(m->streams),
|
||||||
|
+ (int)h2_ihash_count(m->shold), (int)h2_ihash_count(m->spurge), m->tasks_active);
|
||||||
|
while (!h2_ihash_iter(m->streams, stream_cancel_iter, m)) {
|
||||||
|
/* until empty */
|
||||||
|
}
|
||||||
|
@@ -456,10 +463,10 @@ void h2_mplx_release_and_join(h2_mplx *m, apr_thread_cond_t *wait)
|
||||||
|
h2_ihash_iter(m->shold, report_stream_iter, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- ap_assert(m->tasks_active == 0);
|
||||||
|
m->join_wait = NULL;
|
||||||
|
-
|
||||||
|
+
|
||||||
|
/* 4. With all workers done, all streams should be in spurge */
|
||||||
|
+ ap_assert(m->tasks_active == 0);
|
||||||
|
if (!h2_ihash_empty(m->shold)) {
|
||||||
|
ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, m->c, APLOGNO(03516)
|
||||||
|
"h2_mplx(%ld): unexpected %d streams in hold",
|
||||||
|
@@ -470,8 +477,7 @@ void h2_mplx_release_and_join(h2_mplx *m, apr_thread_cond_t *wait)
|
||||||
|
m->c->aborted = old_aborted;
|
||||||
|
H2_MPLX_LEAVE(m);
|
||||||
|
|
||||||
|
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
|
||||||
|
- "h2_mplx(%ld): released", m->id);
|
||||||
|
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c, "h2_mplx(%ld): released", m->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
apr_status_t h2_mplx_stream_cleanup(h2_mplx *m, h2_stream *stream)
|
||||||
|
@@ -709,7 +715,6 @@ static h2_task *next_stream_task(h2_mplx *m)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stream->task) {
|
||||||
|
-
|
||||||
|
if (sid > m->max_stream_started) {
|
||||||
|
m->max_stream_started = sid;
|
||||||
|
}
|
||||||
|
@@ -728,9 +733,9 @@ static h2_task *next_stream_task(h2_mplx *m)
|
||||||
|
"create task"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
-
|
||||||
|
}
|
||||||
|
|
||||||
|
+ stream->task->started_at = apr_time_now();
|
||||||
|
++m->tasks_active;
|
||||||
|
return stream->task;
|
||||||
|
}
|
||||||
|
@@ -778,32 +783,18 @@ static void task_done(h2_mplx *m, h2_task *task)
|
||||||
|
"h2_mplx(%s): request done, %f ms elapsed", task->id,
|
||||||
|
(task->done_at - task->started_at) / 1000.0);
|
||||||
|
|
||||||
|
- if (task->started_at > m->last_idle_block) {
|
||||||
|
- /* this task finished without causing an 'idle block', e.g.
|
||||||
|
- * a block by flow control.
|
||||||
|
- */
|
||||||
|
- if (task->done_at- m->last_limit_change >= m->limit_change_interval
|
||||||
|
- && m->limit_active < m->max_active) {
|
||||||
|
- /* Well behaving stream, allow it more workers */
|
||||||
|
- m->limit_active = H2MIN(m->limit_active * 2,
|
||||||
|
- m->max_active);
|
||||||
|
- m->last_limit_change = task->done_at;
|
||||||
|
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
|
||||||
|
- "h2_mplx(%ld): increase worker limit to %d",
|
||||||
|
- m->id, m->limit_active);
|
||||||
|
- }
|
||||||
|
+ if (task->c && !task->c->aborted && task->started_at > m->last_mood_change) {
|
||||||
|
+ mplx_be_happy(m);
|
||||||
|
}
|
||||||
|
-
|
||||||
|
+
|
||||||
|
ap_assert(task->done_done == 0);
|
||||||
|
|
||||||
|
stream = h2_ihash_get(m->streams, task->stream_id);
|
||||||
|
if (stream) {
|
||||||
|
/* stream not done yet. */
|
||||||
|
- if (!m->aborted && h2_ihash_get(m->sredo, stream->id)) {
|
||||||
|
+ if (!m->aborted && task->redo) {
|
||||||
|
/* reset and schedule again */
|
||||||
|
- task->worker_done = 0;
|
||||||
|
h2_task_redo(task);
|
||||||
|
- h2_ihash_remove(m->sredo, stream->id);
|
||||||
|
h2_iq_add(m->q, stream->id, NULL, NULL);
|
||||||
|
ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, m->c,
|
||||||
|
H2_STRM_MSG(stream, "redo, added to q"));
|
||||||
|
@@ -848,8 +839,8 @@ void h2_mplx_task_done(h2_mplx *m, h2_task *task, h2_task **ptask)
|
||||||
|
{
|
||||||
|
H2_MPLX_ENTER_ALWAYS(m);
|
||||||
|
|
||||||
|
- task_done(m, task);
|
||||||
|
--m->tasks_active;
|
||||||
|
+ task_done(m, task);
|
||||||
|
|
||||||
|
if (m->join_wait) {
|
||||||
|
apr_thread_cond_signal(m->join_wait);
|
||||||
|
@@ -867,94 +858,161 @@ void h2_mplx_task_done(h2_mplx *m, h2_task *task, h2_task **ptask)
|
||||||
|
* h2_mplx DoS protection
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
-static int latest_repeatable_unsubmitted_iter(void *data, void *val)
|
||||||
|
+static int timed_out_busy_iter(void *data, void *val)
|
||||||
|
{
|
||||||
|
stream_iter_ctx *ctx = data;
|
||||||
|
h2_stream *stream = val;
|
||||||
|
-
|
||||||
|
- if (stream->task && !stream->task->worker_done
|
||||||
|
- && h2_task_can_redo(stream->task)
|
||||||
|
- && !h2_ihash_get(ctx->m->sredo, stream->id)) {
|
||||||
|
- if (!h2_stream_is_ready(stream)) {
|
||||||
|
- /* this task occupies a worker, the response has not been submitted
|
||||||
|
- * yet, not been cancelled and it is a repeatable request
|
||||||
|
- * -> it can be re-scheduled later */
|
||||||
|
- if (!ctx->stream
|
||||||
|
- || (ctx->stream->task->started_at < stream->task->started_at)) {
|
||||||
|
- /* we did not have one or this one was started later */
|
||||||
|
- ctx->stream = stream;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
+ if (h2_task_has_started(stream->task) && !stream->task->worker_done
|
||||||
|
+ && (ctx->now - stream->task->started_at) > stream->task->timeout) {
|
||||||
|
+ /* timed out stream occupying a worker, found */
|
||||||
|
+ ctx->stream = stream;
|
||||||
|
+ return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static h2_stream *get_latest_repeatable_unsubmitted_stream(h2_mplx *m)
|
||||||
|
+static h2_stream *get_timed_out_busy_stream(h2_mplx *m)
|
||||||
|
{
|
||||||
|
stream_iter_ctx ctx;
|
||||||
|
ctx.m = m;
|
||||||
|
ctx.stream = NULL;
|
||||||
|
- h2_ihash_iter(m->streams, latest_repeatable_unsubmitted_iter, &ctx);
|
||||||
|
+ ctx.now = apr_time_now();
|
||||||
|
+ h2_ihash_iter(m->streams, timed_out_busy_iter, &ctx);
|
||||||
|
return ctx.stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static int timed_out_busy_iter(void *data, void *val)
|
||||||
|
+static int latest_repeatable_unsubmitted_iter(void *data, void *val)
|
||||||
|
{
|
||||||
|
stream_iter_ctx *ctx = data;
|
||||||
|
h2_stream *stream = val;
|
||||||
|
- if (stream->task && !stream->task->worker_done
|
||||||
|
- && (ctx->now - stream->task->started_at) > stream->task->timeout) {
|
||||||
|
- /* timed out stream occupying a worker, found */
|
||||||
|
- ctx->stream = stream;
|
||||||
|
- return 0;
|
||||||
|
+
|
||||||
|
+ if (!stream->task) goto leave;
|
||||||
|
+ if (!h2_task_has_started(stream->task) || stream->task->worker_done) goto leave;
|
||||||
|
+ if (h2_stream_is_ready(stream)) goto leave;
|
||||||
|
+ if (stream->task->redo) {
|
||||||
|
+ ++ctx->count;
|
||||||
|
+ goto leave;
|
||||||
|
+ }
|
||||||
|
+ if (h2_task_can_redo(stream->task)) {
|
||||||
|
+ /* this task occupies a worker, the response has not been submitted
|
||||||
|
+ * yet, not been cancelled and it is a repeatable request
|
||||||
|
+ * -> we could redo it later */
|
||||||
|
+ if (!ctx->stream
|
||||||
|
+ || (ctx->stream->task->started_at < stream->task->started_at)) {
|
||||||
|
+ /* we did not have one or this one was started later */
|
||||||
|
+ ctx->stream = stream;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
+leave:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static h2_stream *get_timed_out_busy_stream(h2_mplx *m)
|
||||||
|
+static apr_status_t assess_task_to_throttle(h2_task **ptask, h2_mplx *m)
|
||||||
|
{
|
||||||
|
stream_iter_ctx ctx;
|
||||||
|
+
|
||||||
|
+ /* count the running tasks already marked for redo and get one that could
|
||||||
|
+ * be throttled */
|
||||||
|
+ *ptask = NULL;
|
||||||
|
ctx.m = m;
|
||||||
|
ctx.stream = NULL;
|
||||||
|
- ctx.now = apr_time_now();
|
||||||
|
- h2_ihash_iter(m->streams, timed_out_busy_iter, &ctx);
|
||||||
|
- return ctx.stream;
|
||||||
|
+ ctx.count = 0;
|
||||||
|
+ h2_ihash_iter(m->streams, latest_repeatable_unsubmitted_iter, &ctx);
|
||||||
|
+ if (m->tasks_active - ctx.count > m->limit_active) {
|
||||||
|
+ /* we are above the limit of running tasks, accounting for the ones
|
||||||
|
+ * already throttled. */
|
||||||
|
+ if (ctx.stream && ctx.stream->task) {
|
||||||
|
+ *ptask = ctx.stream->task;
|
||||||
|
+ return APR_EAGAIN;
|
||||||
|
+ }
|
||||||
|
+ /* above limit, be seeing no candidate for easy throttling */
|
||||||
|
+ if (get_timed_out_busy_stream(m)) {
|
||||||
|
+ /* Too many busy workers, unable to cancel enough streams
|
||||||
|
+ * and with a busy, timed out stream, we tell the client
|
||||||
|
+ * to go away... */
|
||||||
|
+ return APR_TIMEUP;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return APR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static apr_status_t unschedule_slow_tasks(h2_mplx *m)
|
||||||
|
{
|
||||||
|
- h2_stream *stream;
|
||||||
|
- int n;
|
||||||
|
+ h2_task *task;
|
||||||
|
+ apr_status_t rv;
|
||||||
|
|
||||||
|
/* Try to get rid of streams that occupy workers. Look for safe requests
|
||||||
|
* that are repeatable. If none found, fail the connection.
|
||||||
|
*/
|
||||||
|
- n = (m->tasks_active - m->limit_active - (int)h2_ihash_count(m->sredo));
|
||||||
|
- while (n > 0 && (stream = get_latest_repeatable_unsubmitted_stream(m))) {
|
||||||
|
+ while (APR_EAGAIN == (rv = assess_task_to_throttle(&task, m))) {
|
||||||
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
|
||||||
|
"h2_mplx(%s): unschedule, resetting task for redo later",
|
||||||
|
- stream->task->id);
|
||||||
|
- h2_task_rst(stream->task, H2_ERR_CANCEL);
|
||||||
|
- h2_ihash_add(m->sredo, stream);
|
||||||
|
- --n;
|
||||||
|
+ task->id);
|
||||||
|
+ task->redo = 1;
|
||||||
|
+ h2_task_rst(task, H2_ERR_CANCEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
- if ((m->tasks_active - h2_ihash_count(m->sredo)) > m->limit_active) {
|
||||||
|
- h2_stream *stream = get_timed_out_busy_stream(m);
|
||||||
|
- if (stream) {
|
||||||
|
- /* Too many busy workers, unable to cancel enough streams
|
||||||
|
- * and with a busy, timed out stream, we tell the client
|
||||||
|
- * to go away... */
|
||||||
|
- return APR_TIMEUP;
|
||||||
|
- }
|
||||||
|
+ return rv;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static apr_status_t mplx_be_happy(h2_mplx *m)
|
||||||
|
+{
|
||||||
|
+ apr_time_t now;
|
||||||
|
+
|
||||||
|
+ --m->irritations_since;
|
||||||
|
+ now = apr_time_now();
|
||||||
|
+ if (m->limit_active < m->max_active
|
||||||
|
+ && (now - m->last_mood_change >= m->mood_update_interval
|
||||||
|
+ || m->irritations_since < -m->limit_active)) {
|
||||||
|
+ m->limit_active = H2MIN(m->limit_active * 2, m->max_active);
|
||||||
|
+ m->last_mood_change = now;
|
||||||
|
+ m->irritations_since = 0;
|
||||||
|
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
|
||||||
|
+ "h2_mplx(%ld): mood update, increasing worker limit to %d",
|
||||||
|
+ m->id, m->limit_active);
|
||||||
|
}
|
||||||
|
return APR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
-apr_status_t h2_mplx_idle(h2_mplx *m)
|
||||||
|
+static apr_status_t mplx_be_annoyed(h2_mplx *m)
|
||||||
|
{
|
||||||
|
apr_status_t status = APR_SUCCESS;
|
||||||
|
apr_time_t now;
|
||||||
|
+
|
||||||
|
+ ++m->irritations_since;
|
||||||
|
+ now = apr_time_now();
|
||||||
|
+ if (m->limit_active > 2 &&
|
||||||
|
+ ((now - m->last_mood_change >= m->mood_update_interval)
|
||||||
|
+ || (m->irritations_since >= m->limit_active))) {
|
||||||
|
+
|
||||||
|
+ if (m->limit_active > 16) {
|
||||||
|
+ m->limit_active = 16;
|
||||||
|
+ }
|
||||||
|
+ else if (m->limit_active > 8) {
|
||||||
|
+ m->limit_active = 8;
|
||||||
|
+ }
|
||||||
|
+ else if (m->limit_active > 4) {
|
||||||
|
+ m->limit_active = 4;
|
||||||
|
+ }
|
||||||
|
+ else if (m->limit_active > 2) {
|
||||||
|
+ m->limit_active = 2;
|
||||||
|
+ }
|
||||||
|
+ m->last_mood_change = now;
|
||||||
|
+ m->irritations_since = 0;
|
||||||
|
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
|
||||||
|
+ "h2_mplx(%ld): mood update, decreasing worker limit to %d",
|
||||||
|
+ m->id, m->limit_active);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (m->tasks_active > m->limit_active) {
|
||||||
|
+ status = unschedule_slow_tasks(m);
|
||||||
|
+ }
|
||||||
|
+ return status;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+apr_status_t h2_mplx_idle(h2_mplx *m)
|
||||||
|
+{
|
||||||
|
+ apr_status_t status = APR_SUCCESS;
|
||||||
|
apr_size_t scount;
|
||||||
|
|
||||||
|
H2_MPLX_ENTER(m);
|
||||||
|
@@ -974,31 +1032,7 @@ apr_status_t h2_mplx_idle(h2_mplx *m)
|
||||||
|
* of busy workers we allow for this connection until it
|
||||||
|
* well behaves.
|
||||||
|
*/
|
||||||
|
- now = apr_time_now();
|
||||||
|
- m->last_idle_block = now;
|
||||||
|
- if (m->limit_active > 2
|
||||||
|
- && now - m->last_limit_change >= m->limit_change_interval) {
|
||||||
|
- if (m->limit_active > 16) {
|
||||||
|
- m->limit_active = 16;
|
||||||
|
- }
|
||||||
|
- else if (m->limit_active > 8) {
|
||||||
|
- m->limit_active = 8;
|
||||||
|
- }
|
||||||
|
- else if (m->limit_active > 4) {
|
||||||
|
- m->limit_active = 4;
|
||||||
|
- }
|
||||||
|
- else if (m->limit_active > 2) {
|
||||||
|
- m->limit_active = 2;
|
||||||
|
- }
|
||||||
|
- m->last_limit_change = now;
|
||||||
|
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
|
||||||
|
- "h2_mplx(%ld): decrease worker limit to %d",
|
||||||
|
- m->id, m->limit_active);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- if (m->tasks_active > m->limit_active) {
|
||||||
|
- status = unschedule_slow_tasks(m);
|
||||||
|
- }
|
||||||
|
+ status = mplx_be_annoyed(m);
|
||||||
|
}
|
||||||
|
else if (!h2_iq_empty(m->q)) {
|
||||||
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
|
||||||
|
@@ -1093,11 +1127,24 @@ int h2_mplx_awaits_data(h2_mplx *m)
|
||||||
|
if (h2_ihash_empty(m->streams)) {
|
||||||
|
waiting = 0;
|
||||||
|
}
|
||||||
|
- else if (!m->tasks_active && !h2_ififo_count(m->readyq)
|
||||||
|
- && h2_iq_empty(m->q)) {
|
||||||
|
+ else if (!m->tasks_active && !h2_ififo_count(m->readyq) && h2_iq_empty(m->q)) {
|
||||||
|
waiting = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
H2_MPLX_LEAVE(m);
|
||||||
|
return waiting;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+apr_status_t h2_mplx_client_rst(h2_mplx *m, int stream_id)
|
||||||
|
+{
|
||||||
|
+ h2_stream *stream;
|
||||||
|
+ apr_status_t status = APR_SUCCESS;
|
||||||
|
+
|
||||||
|
+ H2_MPLX_ENTER_ALWAYS(m);
|
||||||
|
+ stream = h2_ihash_get(m->streams, stream_id);
|
||||||
|
+ if (stream && stream->task) {
|
||||||
|
+ status = mplx_be_annoyed(m);
|
||||||
|
+ }
|
||||||
|
+ H2_MPLX_LEAVE(m);
|
||||||
|
+ return status;
|
||||||
|
+}
|
||||||
|
diff --git a/modules/http2/h2_mplx.h b/modules/http2/h2_mplx.h
|
||||||
|
index 575ccaf..8a4f63f 100644
|
||||||
|
--- a/modules/http2/h2_mplx.h
|
||||||
|
+++ b/modules/http2/h2_mplx.h
|
||||||
|
@@ -63,7 +63,6 @@ struct h2_mplx {
|
||||||
|
unsigned int is_registered; /* is registered at h2_workers */
|
||||||
|
|
||||||
|
struct h2_ihash_t *streams; /* all streams currently processing */
|
||||||
|
- struct h2_ihash_t *sredo; /* all streams that need to be re-started */
|
||||||
|
struct h2_ihash_t *shold; /* all streams done with task ongoing */
|
||||||
|
struct h2_ihash_t *spurge; /* all streams done, ready for destroy */
|
||||||
|
|
||||||
|
@@ -77,10 +76,10 @@ struct h2_mplx {
|
||||||
|
int tasks_active; /* # of tasks being processed from this mplx */
|
||||||
|
int limit_active; /* current limit on active tasks, dynamic */
|
||||||
|
int max_active; /* max, hard limit # of active tasks in a process */
|
||||||
|
- apr_time_t last_idle_block; /* last time, this mplx entered IDLE while
|
||||||
|
- * streams were ready */
|
||||||
|
- apr_time_t last_limit_change; /* last time, worker limit changed */
|
||||||
|
- apr_interval_time_t limit_change_interval;
|
||||||
|
+
|
||||||
|
+ apr_time_t last_mood_change; /* last time, we worker limit changed */
|
||||||
|
+ apr_interval_time_t mood_update_interval; /* how frequent we update at most */
|
||||||
|
+ int irritations_since; /* irritations (>0) or happy events (<0) since last mood change */
|
||||||
|
|
||||||
|
apr_thread_mutex_t *lock;
|
||||||
|
struct apr_thread_cond_t *added_output;
|
||||||
|
@@ -205,6 +204,8 @@ typedef int h2_mplx_stream_cb(struct h2_stream *s, void *ctx);
|
||||||
|
|
||||||
|
apr_status_t h2_mplx_stream_do(h2_mplx *m, h2_mplx_stream_cb *cb, void *ctx);
|
||||||
|
|
||||||
|
+apr_status_t h2_mplx_client_rst(h2_mplx *m, int stream_id);
|
||||||
|
+
|
||||||
|
/*******************************************************************************
|
||||||
|
* Output handling of streams.
|
||||||
|
******************************************************************************/
|
||||||
|
diff --git a/modules/http2/h2_session.c b/modules/http2/h2_session.c
|
||||||
|
index f153422..43d26d3 100644
|
||||||
|
--- a/modules/http2/h2_session.c
|
||||||
|
+++ b/modules/http2/h2_session.c
|
||||||
|
@@ -390,9 +390,14 @@ static int on_frame_recv_cb(nghttp2_session *ng2s,
|
||||||
|
(int)frame->rst_stream.error_code);
|
||||||
|
stream = h2_session_stream_get(session, frame->hd.stream_id);
|
||||||
|
if (stream && stream->initiated_on) {
|
||||||
|
+ /* A stream reset on a request we sent it. Normal, when the
|
||||||
|
+ * client does not want it. */
|
||||||
|
++session->pushes_reset;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
+ /* A stream reset on a request it sent us. Could happen in a browser
|
||||||
|
+ * when the user navigates away or cancels loading - maybe. */
|
||||||
|
+ h2_mplx_client_rst(session->mplx, frame->hd.stream_id);
|
||||||
|
++session->streams_reset;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
@@ -1699,7 +1704,7 @@ static void transit(h2_session *session, const char *action, h2_session_state ns
|
||||||
|
* that already served requests - not fair. */
|
||||||
|
session->idle_sync_until = apr_time_now() + apr_time_from_sec(1);
|
||||||
|
s = "timeout";
|
||||||
|
- timeout = H2MAX(session->s->timeout, session->s->keep_alive_timeout);
|
||||||
|
+ timeout = session->s->timeout;
|
||||||
|
update_child_status(session, SERVER_BUSY_READ, "idle");
|
||||||
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, session->c,
|
||||||
|
H2_SSSN_LOG("", session, "enter idle, timeout = %d sec"),
|
||||||
|
@@ -1707,8 +1712,8 @@ static void transit(h2_session *session, const char *action, h2_session_state ns
|
||||||
|
}
|
||||||
|
else if (session->open_streams) {
|
||||||
|
s = "timeout";
|
||||||
|
- timeout = session->s->keep_alive_timeout;
|
||||||
|
- update_child_status(session, SERVER_BUSY_KEEPALIVE, "idle");
|
||||||
|
+ timeout = session->s->timeout;
|
||||||
|
+ update_child_status(session, SERVER_BUSY_READ, "idle");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* normal keepalive setup */
|
||||||
|
@@ -2166,6 +2171,14 @@ apr_status_t h2_session_process(h2_session *session, int async)
|
||||||
|
session->have_read = 1;
|
||||||
|
}
|
||||||
|
else if (APR_STATUS_IS_EAGAIN(status) || APR_STATUS_IS_TIMEUP(status)) {
|
||||||
|
+ status = h2_mplx_idle(session->mplx);
|
||||||
|
+ if (status == APR_EAGAIN) {
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ else if (status != APR_SUCCESS) {
|
||||||
|
+ dispatch_event(session, H2_SESSION_EV_CONN_ERROR,
|
||||||
|
+ H2_ERR_ENHANCE_YOUR_CALM, "less is more");
|
||||||
|
+ }
|
||||||
|
status = APR_EAGAIN;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
diff --git a/modules/http2/h2_stream.c b/modules/http2/h2_stream.c
|
||||||
|
index b5763ac..8c3d305 100644
|
||||||
|
--- a/modules/http2/h2_stream.c
|
||||||
|
+++ b/modules/http2/h2_stream.c
|
||||||
|
@@ -397,13 +397,8 @@ apr_status_t h2_stream_send_frame(h2_stream *stream, int ftype, int flags, size_
|
||||||
|
/* start pushed stream */
|
||||||
|
ap_assert(stream->request == NULL);
|
||||||
|
ap_assert(stream->rtmp != NULL);
|
||||||
|
- status = h2_request_end_headers(stream->rtmp, stream->pool, 1, 0);
|
||||||
|
- if (status != APR_SUCCESS) {
|
||||||
|
- return status;
|
||||||
|
- }
|
||||||
|
- set_policy_for(stream, stream->rtmp);
|
||||||
|
- stream->request = stream->rtmp;
|
||||||
|
- stream->rtmp = NULL;
|
||||||
|
+ status = h2_stream_end_headers(stream, 1, 0);
|
||||||
|
+ if (status != APR_SUCCESS) goto leave;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
@@ -415,6 +410,7 @@ apr_status_t h2_stream_send_frame(h2_stream *stream, int ftype, int flags, size_
|
||||||
|
if (status == APR_SUCCESS && eos) {
|
||||||
|
status = transit(stream, on_event(stream, H2_SEV_CLOSED_L));
|
||||||
|
}
|
||||||
|
+leave:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -455,13 +451,8 @@ apr_status_t h2_stream_recv_frame(h2_stream *stream, int ftype, int flags, size_
|
||||||
|
* to abort the connection here, since this is clearly a protocol error */
|
||||||
|
return APR_EINVAL;
|
||||||
|
}
|
||||||
|
- status = h2_request_end_headers(stream->rtmp, stream->pool, eos, frame_len);
|
||||||
|
- if (status != APR_SUCCESS) {
|
||||||
|
- return status;
|
||||||
|
- }
|
||||||
|
- set_policy_for(stream, stream->rtmp);
|
||||||
|
- stream->request = stream->rtmp;
|
||||||
|
- stream->rtmp = NULL;
|
||||||
|
+ status = h2_stream_end_headers(stream, eos, frame_len);
|
||||||
|
+ if (status != APR_SUCCESS) goto leave;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
@@ -472,6 +463,7 @@ apr_status_t h2_stream_recv_frame(h2_stream *stream, int ftype, int flags, size_
|
||||||
|
if (status == APR_SUCCESS && eos) {
|
||||||
|
status = transit(stream, on_event(stream, H2_SEV_CLOSED_R));
|
||||||
|
}
|
||||||
|
+leave:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -683,6 +675,8 @@ static apr_status_t add_trailer(h2_stream *stream,
|
||||||
|
hvalue = apr_pstrndup(stream->pool, value, vlen);
|
||||||
|
h2_util_camel_case_header(hname, nlen);
|
||||||
|
apr_table_mergen(stream->trailers, hname, hvalue);
|
||||||
|
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
|
||||||
|
+ H2_STRM_MSG(stream, "added trailer '%s: %s'"), hname, hvalue);
|
||||||
|
|
||||||
|
return APR_SUCCESS;
|
||||||
|
}
|
||||||
|
@@ -702,15 +696,19 @@ apr_status_t h2_stream_add_header(h2_stream *stream,
|
||||||
|
if (name[0] == ':') {
|
||||||
|
if ((vlen) > session->s->limit_req_line) {
|
||||||
|
/* pseudo header: approximation of request line size check */
|
||||||
|
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, session->c,
|
||||||
|
- H2_STRM_MSG(stream, "pseudo %s too long"), name);
|
||||||
|
+ ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, session->c,
|
||||||
|
+ H2_STRM_LOG(APLOGNO(10178), stream,
|
||||||
|
+ "Request pseudo header exceeds "
|
||||||
|
+ "LimitRequestFieldSize: %s"), name);
|
||||||
|
error = HTTP_REQUEST_URI_TOO_LARGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((nlen + 2 + vlen) > session->s->limit_req_fieldsize) {
|
||||||
|
/* header too long */
|
||||||
|
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, session->c,
|
||||||
|
- H2_STRM_MSG(stream, "header %s too long"), name);
|
||||||
|
+ ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, session->c,
|
||||||
|
+ H2_STRM_LOG(APLOGNO(10180), stream,"Request header exceeds "
|
||||||
|
+ "LimitRequestFieldSize: %.*s"),
|
||||||
|
+ (int)H2MIN(nlen, 80), name);
|
||||||
|
error = HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -722,8 +720,9 @@ apr_status_t h2_stream_add_header(h2_stream *stream,
|
||||||
|
h2_stream_rst(stream, H2_ERR_ENHANCE_YOUR_CALM);
|
||||||
|
return APR_ECONNRESET;
|
||||||
|
}
|
||||||
|
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, session->c,
|
||||||
|
- H2_STRM_MSG(stream, "too many header lines"));
|
||||||
|
+ ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, session->c,
|
||||||
|
+ H2_STRM_LOG(APLOGNO(10181), stream, "Number of request headers "
|
||||||
|
+ "exceeds LimitRequestFields"));
|
||||||
|
error = HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -754,6 +753,47 @@ apr_status_t h2_stream_add_header(h2_stream *stream,
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
+typedef struct {
|
||||||
|
+ apr_size_t maxlen;
|
||||||
|
+ const char *failed_key;
|
||||||
|
+} val_len_check_ctx;
|
||||||
|
+
|
||||||
|
+static int table_check_val_len(void *baton, const char *key, const char *value)
|
||||||
|
+{
|
||||||
|
+ val_len_check_ctx *ctx = baton;
|
||||||
|
+
|
||||||
|
+ if (strlen(value) <= ctx->maxlen) return 1;
|
||||||
|
+ ctx->failed_key = key;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+apr_status_t h2_stream_end_headers(h2_stream *stream, int eos, size_t raw_bytes)
|
||||||
|
+{
|
||||||
|
+ apr_status_t status;
|
||||||
|
+ val_len_check_ctx ctx;
|
||||||
|
+
|
||||||
|
+ status = h2_request_end_headers(stream->rtmp, stream->pool, eos, raw_bytes);
|
||||||
|
+ if (APR_SUCCESS == status) {
|
||||||
|
+ set_policy_for(stream, stream->rtmp);
|
||||||
|
+ stream->request = stream->rtmp;
|
||||||
|
+ stream->rtmp = NULL;
|
||||||
|
+
|
||||||
|
+ ctx.maxlen = stream->session->s->limit_req_fieldsize;
|
||||||
|
+ ctx.failed_key = NULL;
|
||||||
|
+ apr_table_do(table_check_val_len, &ctx, stream->request->headers, NULL);
|
||||||
|
+ if (ctx.failed_key) {
|
||||||
|
+ ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, stream->session->c,
|
||||||
|
+ H2_STRM_LOG(APLOGNO(), stream,"Request header exceeds "
|
||||||
|
+ "LimitRequestFieldSize: %.*s"),
|
||||||
|
+ (int)H2MIN(strlen(ctx.failed_key), 80), ctx.failed_key);
|
||||||
|
+ set_error_response(stream, HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE);
|
||||||
|
+ /* keep on returning APR_SUCCESS, so that we send a HTTP response and
|
||||||
|
+ * do not RST the stream. */
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return status;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static apr_bucket *get_first_headers_bucket(apr_bucket_brigade *bb)
|
||||||
|
{
|
||||||
|
if (bb) {
|
||||||
|
diff --git a/modules/http2/h2_stream.h b/modules/http2/h2_stream.h
|
||||||
|
index 7ecc0ad..79cb39d 100644
|
||||||
|
--- a/modules/http2/h2_stream.h
|
||||||
|
+++ b/modules/http2/h2_stream.h
|
||||||
|
@@ -198,6 +198,10 @@ apr_status_t h2_stream_set_request_rec(h2_stream *stream,
|
||||||
|
apr_status_t h2_stream_add_header(h2_stream *stream,
|
||||||
|
const char *name, size_t nlen,
|
||||||
|
const char *value, size_t vlen);
|
||||||
|
+
|
||||||
|
+/* End the contruction of request headers */
|
||||||
|
+apr_status_t h2_stream_end_headers(h2_stream *stream, int eos, size_t raw_bytes);
|
||||||
|
+
|
||||||
|
|
||||||
|
apr_status_t h2_stream_send_frame(h2_stream *stream, int frame_type, int flags, size_t frame_len);
|
||||||
|
apr_status_t h2_stream_recv_frame(h2_stream *stream, int frame_type, int flags, size_t frame_len);
|
||||||
|
diff --git a/modules/http2/h2_task.c b/modules/http2/h2_task.c
|
||||||
|
index a395807..c312459 100644
|
||||||
|
--- a/modules/http2/h2_task.c
|
||||||
|
+++ b/modules/http2/h2_task.c
|
||||||
|
@@ -408,8 +408,15 @@ int h2_task_can_redo(h2_task *task) {
|
||||||
|
|| !strcmp("OPTIONS", task->request->method));
|
||||||
|
}
|
||||||
|
|
||||||
|
+int h2_task_has_started(h2_task *task)
|
||||||
|
+{
|
||||||
|
+ return task && task->started_at != 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void h2_task_redo(h2_task *task)
|
||||||
|
{
|
||||||
|
+ task->started_at = 0;
|
||||||
|
+ task->worker_done = 0;
|
||||||
|
task->rst_error = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -548,7 +555,6 @@ apr_status_t h2_task_do(h2_task *task, apr_thread_t *thread, int worker_id)
|
||||||
|
ap_assert(task);
|
||||||
|
c = task->c;
|
||||||
|
task->worker_started = 1;
|
||||||
|
- task->started_at = apr_time_now();
|
||||||
|
|
||||||
|
if (c->master) {
|
||||||
|
/* Each conn_rec->id is supposed to be unique at a point in time. Since
|
||||||
|
diff --git a/modules/http2/h2_task.h b/modules/http2/h2_task.h
|
||||||
|
index 20be429..9a7ad68 100644
|
||||||
|
--- a/modules/http2/h2_task.h
|
||||||
|
+++ b/modules/http2/h2_task.h
|
||||||
|
@@ -80,6 +80,7 @@ struct h2_task {
|
||||||
|
|
||||||
|
unsigned int filters_set : 1;
|
||||||
|
unsigned int worker_started : 1; /* h2_worker started processing */
|
||||||
|
+ unsigned int redo : 1; /* was throttled, should be restarted later */
|
||||||
|
|
||||||
|
int worker_done; /* h2_worker finished */
|
||||||
|
int done_done; /* task_done has been handled */
|
||||||
|
@@ -101,6 +102,7 @@ apr_status_t h2_task_do(h2_task *task, apr_thread_t *thread, int worker_id);
|
||||||
|
|
||||||
|
void h2_task_redo(h2_task *task);
|
||||||
|
int h2_task_can_redo(h2_task *task);
|
||||||
|
+int h2_task_has_started(h2_task *task);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the task with the given error code, resets all input/output.
|
||||||
|
diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c
|
||||||
|
index 048ae61..7a8a197 100644
|
||||||
|
--- a/server/mpm/event/event.c
|
||||||
|
+++ b/server/mpm/event/event.c
|
||||||
|
@@ -1112,10 +1112,11 @@ read_request:
|
||||||
|
"network write failure in core output filter");
|
||||||
|
cs->pub.state = CONN_STATE_LINGER;
|
||||||
|
}
|
||||||
|
- else if (c->data_in_output_filters) {
|
||||||
|
+ else if (c->data_in_output_filters ||
|
||||||
|
+ cs->pub.sense == CONN_SENSE_WANT_READ) {
|
||||||
|
/* Still in WRITE_COMPLETION_STATE:
|
||||||
|
- * Set a write timeout for this connection, and let the
|
||||||
|
- * event thread poll for writeability.
|
||||||
|
+ * Set a read/write timeout for this connection, and let the
|
||||||
|
+ * event thread poll for read/writeability.
|
||||||
|
*/
|
||||||
|
cs->queue_timestamp = apr_time_now();
|
||||||
|
notify_suspend(cs);
|
||||||
|
--
|
||||||
|
1.8.3.1
|
||||||
|
|
||||||
73
CVE-2020-1927-1.patch
Normal file
73
CVE-2020-1927-1.patch
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
From f11d5830759eb50ed366fc0690f9f4f491064ea3 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jim Jagielski <jim@apache.org>
|
||||||
|
Date: Tue, 11 Feb 2020 13:16:38 +0000
|
||||||
|
Subject: [PATCH 1/2] Merge r1873747 from trunk:
|
||||||
|
|
||||||
|
factor out default regex flags
|
||||||
|
|
||||||
|
Submitted by: covener
|
||||||
|
Reviewed by: covener, minfrin, jorton
|
||||||
|
|
||||||
|
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1873905 13f79535-47bb-0310-9956-ffa450edef68
|
||||||
|
---
|
||||||
|
include/ap_mmn.h | 1 +
|
||||||
|
include/ap_regex.h | 2 ++
|
||||||
|
server/core.c | 2 +-
|
||||||
|
server/util_pcre.c | 3 +--
|
||||||
|
4 files changed, 5 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/include/ap_mmn.h b/include/ap_mmn.h
|
||||||
|
index 839228e..f5043ef 100644
|
||||||
|
--- a/include/ap_mmn.h
|
||||||
|
+++ b/include/ap_mmn.h
|
||||||
|
@@ -515,6 +515,7 @@
|
||||||
|
* 20120211.77 (2.4.34-dev) Add ap_exists_directive()
|
||||||
|
* 20120211.78 (2.4.34-dev) Add response_field_size to proxy_worker_shared
|
||||||
|
* 20120211.79 (2.4.34-dev) Add AP_GETLINE_NOSPC_EOL flag to http_protocol.h
|
||||||
|
+ * 20120211.90 (2.4.42-dev) AP_REG_DEFAULT macro in ap_regex.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
|
||||||
|
diff --git a/include/ap_regex.h b/include/ap_regex.h
|
||||||
|
index 7d8df79..e651eea 100644
|
||||||
|
--- a/include/ap_regex.h
|
||||||
|
+++ b/include/ap_regex.h
|
||||||
|
@@ -86,6 +86,8 @@ extern "C" {
|
||||||
|
|
||||||
|
#define AP_REG_MATCH "MATCH_" /** suggested prefix for ap_regname */
|
||||||
|
|
||||||
|
+#define AP_REG_DEFAULT (AP_REG_DOTALL|AP_REG_DOLLAR_ENDONLY)
|
||||||
|
+
|
||||||
|
/* Error values: */
|
||||||
|
enum {
|
||||||
|
AP_REG_ASSERT = 1, /** internal error ? */
|
||||||
|
diff --git a/server/core.c b/server/core.c
|
||||||
|
index e892c87..a8772a3 100644
|
||||||
|
--- a/server/core.c
|
||||||
|
+++ b/server/core.c
|
||||||
|
@@ -4938,7 +4938,7 @@ static int core_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptem
|
||||||
|
apr_pool_cleanup_register(pconf, NULL, reset_config_defines,
|
||||||
|
apr_pool_cleanup_null);
|
||||||
|
|
||||||
|
- ap_regcomp_set_default_cflags(AP_REG_DOLLAR_ENDONLY);
|
||||||
|
+ ap_regcomp_set_default_cflags(AP_REG_DEFAULT);
|
||||||
|
|
||||||
|
mpm_common_pre_config(pconf);
|
||||||
|
|
||||||
|
diff --git a/server/util_pcre.c b/server/util_pcre.c
|
||||||
|
index 35831f5..74722b4 100644
|
||||||
|
--- a/server/util_pcre.c
|
||||||
|
+++ b/server/util_pcre.c
|
||||||
|
@@ -120,8 +120,7 @@ AP_DECLARE(void) ap_regfree(ap_regex_t *preg)
|
||||||
|
* Compile a regular expression *
|
||||||
|
*************************************************/
|
||||||
|
|
||||||
|
-static int default_cflags = AP_REG_DOTALL |
|
||||||
|
- AP_REG_DOLLAR_ENDONLY;
|
||||||
|
+static int default_cflags = AP_REG_DEFAULT;
|
||||||
|
|
||||||
|
AP_DECLARE(int) ap_regcomp_get_default_cflags(void)
|
||||||
|
{
|
||||||
|
--
|
||||||
|
1.8.3.1
|
||||||
|
|
||||||
99
CVE-2020-1927-2.patch
Normal file
99
CVE-2020-1927-2.patch
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
From ff36010963d1c2f2e6b331aa6d7d7d879e3975f6 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Eric Covener <covener@apache.org>
|
||||||
|
Date: Wed, 19 Feb 2020 12:26:31 +0000
|
||||||
|
Subject: [PATCH 2/2] add AP_REG_NO_DEFAULT to allow opt-out of pcre defaults
|
||||||
|
|
||||||
|
... and use it in mod_substitute to avoid DOTALL
|
||||||
|
|
||||||
|
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1874191 13f79535-47bb-0310-9956-ffa450edef68
|
||||||
|
---
|
||||||
|
include/ap_mmn.h | 1 +
|
||||||
|
include/ap_regex.h | 4 +++-
|
||||||
|
modules/filters/mod_substitute.c | 6 ++++--
|
||||||
|
server/util_pcre.c | 4 +++-
|
||||||
|
server/util_regex.c | 3 ++-
|
||||||
|
5 files changed, 13 insertions(+), 5 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/include/ap_mmn.h b/include/ap_mmn.h
|
||||||
|
index f5043ef..4c74e56 100644
|
||||||
|
--- a/include/ap_mmn.h
|
||||||
|
+++ b/include/ap_mmn.h
|
||||||
|
@@ -516,6 +516,7 @@
|
||||||
|
* 20120211.78 (2.4.34-dev) Add response_field_size to proxy_worker_shared
|
||||||
|
* 20120211.79 (2.4.34-dev) Add AP_GETLINE_NOSPC_EOL flag to http_protocol.h
|
||||||
|
* 20120211.90 (2.4.42-dev) AP_REG_DEFAULT macro in ap_regex.h
|
||||||
|
+ * 20120211.92 (2.4.42-dev) AP_REG_NO_DEFAULT macro in ap_regex.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
|
||||||
|
diff --git a/include/ap_regex.h b/include/ap_regex.h
|
||||||
|
index e651eea..7af2f99 100644
|
||||||
|
--- a/include/ap_regex.h
|
||||||
|
+++ b/include/ap_regex.h
|
||||||
|
@@ -84,7 +84,9 @@ extern "C" {
|
||||||
|
|
||||||
|
#define AP_REG_DOLLAR_ENDONLY 0x200 /* '$' matches at end of subject string only */
|
||||||
|
|
||||||
|
-#define AP_REG_MATCH "MATCH_" /** suggested prefix for ap_regname */
|
||||||
|
+#define AP_REG_NO_DEFAULT 0x400 /**< Don't implicitely add AP_REG_DEFAULT options */
|
||||||
|
+
|
||||||
|
+#define AP_REG_MATCH "MATCH_" /**< suggested prefix for ap_regname */
|
||||||
|
|
||||||
|
#define AP_REG_DEFAULT (AP_REG_DOTALL|AP_REG_DOLLAR_ENDONLY)
|
||||||
|
|
||||||
|
diff --git a/modules/filters/mod_substitute.c b/modules/filters/mod_substitute.c
|
||||||
|
index b7d5296..e976c51 100644
|
||||||
|
--- a/modules/filters/mod_substitute.c
|
||||||
|
+++ b/modules/filters/mod_substitute.c
|
||||||
|
@@ -667,8 +667,10 @@ static const char *set_pattern(cmd_parms *cmd, void *cfg, const char *line)
|
||||||
|
|
||||||
|
/* first see if we can compile the regex */
|
||||||
|
if (!is_pattern) {
|
||||||
|
- r = ap_pregcomp(cmd->pool, from, AP_REG_EXTENDED |
|
||||||
|
- (ignore_case ? AP_REG_ICASE : 0));
|
||||||
|
+ int flags = AP_REG_NO_DEFAULT
|
||||||
|
+ | (ap_regcomp_get_default_cflags() & AP_REG_DOLLAR_ENDONLY)
|
||||||
|
+ | (ignore_case ? AP_REG_ICASE : 0);
|
||||||
|
+ r = ap_pregcomp(cmd->pool, from, flags);
|
||||||
|
if (!r)
|
||||||
|
return "Substitute could not compile regex";
|
||||||
|
}
|
||||||
|
diff --git a/server/util_pcre.c b/server/util_pcre.c
|
||||||
|
index 74722b4..8819871 100644
|
||||||
|
--- a/server/util_pcre.c
|
||||||
|
+++ b/server/util_pcre.c
|
||||||
|
@@ -168,7 +168,9 @@ AP_DECLARE(int) ap_regcomp(ap_regex_t * preg, const char *pattern, int cflags)
|
||||||
|
int errcode = 0;
|
||||||
|
int options = PCRE_DUPNAMES;
|
||||||
|
|
||||||
|
- cflags |= default_cflags;
|
||||||
|
+ if ((cflags & AP_REG_NO_DEFAULT) == 0)
|
||||||
|
+ cflags |= default_cflags;
|
||||||
|
+
|
||||||
|
if ((cflags & AP_REG_ICASE) != 0)
|
||||||
|
options |= PCRE_CASELESS;
|
||||||
|
if ((cflags & AP_REG_NEWLINE) != 0)
|
||||||
|
diff --git a/server/util_regex.c b/server/util_regex.c
|
||||||
|
index 2a30d68..5405f8d 100644
|
||||||
|
--- a/server/util_regex.c
|
||||||
|
+++ b/server/util_regex.c
|
||||||
|
@@ -94,6 +94,7 @@ AP_DECLARE(ap_rxplus_t*) ap_rxplus_compile(apr_pool_t *pool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/* anything after the current delimiter is flags */
|
||||||
|
+ ret->flags = ap_regcomp_get_default_cflags() & AP_REG_DOLLAR_ENDONLY;
|
||||||
|
while (*++endp) {
|
||||||
|
switch (*endp) {
|
||||||
|
case 'i': ret->flags |= AP_REG_ICASE; break;
|
||||||
|
@@ -106,7 +107,7 @@ AP_DECLARE(ap_rxplus_t*) ap_rxplus_compile(apr_pool_t *pool,
|
||||||
|
default: break; /* we should probably be stricter here */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- if (ap_regcomp(&ret->rx, rxstr, ret->flags) == 0) {
|
||||||
|
+ if (ap_regcomp(&ret->rx, rxstr, AP_REG_NO_DEFAULT | ret->flags) == 0) {
|
||||||
|
apr_pool_cleanup_register(pool, &ret->rx, rxplus_cleanup,
|
||||||
|
apr_pool_cleanup_null);
|
||||||
|
}
|
||||||
|
--
|
||||||
|
1.8.3.1
|
||||||
|
|
||||||
88
CVE-2020-1934.patch
Normal file
88
CVE-2020-1934.patch
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
From 0b59e8ce2d978dfd6b74473df4e1309a5c226498 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jim Jagielski <jim@apache.org>
|
||||||
|
Date: Tue, 11 Feb 2020 13:14:42 +0000
|
||||||
|
Subject: [PATCH] Merge r1873745 from trunk:
|
||||||
|
|
||||||
|
trap bad FTP responses
|
||||||
|
|
||||||
|
Submitted by: covener
|
||||||
|
Reviewed by: covener, minfrin, jorton
|
||||||
|
|
||||||
|
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1873904 13f79535-47bb-0310-9956-ffa450edef68
|
||||||
|
---
|
||||||
|
modules/proxy/mod_proxy_ftp.c | 20 +++++++++++++++-----
|
||||||
|
1 file changed, 15 insertions(+), 5 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/modules/proxy/mod_proxy_ftp.c b/modules/proxy/mod_proxy_ftp.c
|
||||||
|
index 1557301..6318102 100644
|
||||||
|
--- a/modules/proxy/mod_proxy_ftp.c
|
||||||
|
+++ b/modules/proxy/mod_proxy_ftp.c
|
||||||
|
@@ -218,7 +218,7 @@ static int ftp_check_string(const char *x)
|
||||||
|
* (EBCDIC) machines either.
|
||||||
|
*/
|
||||||
|
static apr_status_t ftp_string_read(conn_rec *c, apr_bucket_brigade *bb,
|
||||||
|
- char *buff, apr_size_t bufflen, int *eos)
|
||||||
|
+ char *buff, apr_size_t bufflen, int *eos, apr_size_t *outlen)
|
||||||
|
{
|
||||||
|
apr_bucket *e;
|
||||||
|
apr_status_t rv;
|
||||||
|
@@ -230,6 +230,7 @@ static apr_status_t ftp_string_read(conn_rec *c, apr_bucket_brigade *bb,
|
||||||
|
/* start with an empty string */
|
||||||
|
buff[0] = 0;
|
||||||
|
*eos = 0;
|
||||||
|
+ *outlen = 0;
|
||||||
|
|
||||||
|
/* loop through each brigade */
|
||||||
|
while (!found) {
|
||||||
|
@@ -273,6 +274,7 @@ static apr_status_t ftp_string_read(conn_rec *c, apr_bucket_brigade *bb,
|
||||||
|
if (len > 0) {
|
||||||
|
memcpy(pos, response, len);
|
||||||
|
pos += len;
|
||||||
|
+ *outlen += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
apr_bucket_delete(e);
|
||||||
|
@@ -385,28 +387,36 @@ static int ftp_getrc_msg(conn_rec *ftp_ctrl, apr_bucket_brigade *bb, char *msgbu
|
||||||
|
char buff[5];
|
||||||
|
char *mb = msgbuf, *me = &msgbuf[msglen];
|
||||||
|
apr_status_t rv;
|
||||||
|
+ apr_size_t nread;
|
||||||
|
+
|
||||||
|
int eos;
|
||||||
|
|
||||||
|
- if (APR_SUCCESS != (rv = ftp_string_read(ftp_ctrl, bb, response, sizeof(response), &eos))) {
|
||||||
|
+ if (APR_SUCCESS != (rv = ftp_string_read(ftp_ctrl, bb, response, sizeof(response), &eos, &nread))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(03233)
|
||||||
|
"<%s", response);
|
||||||
|
*/
|
||||||
|
+ if (nread < 4) {
|
||||||
|
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, APLOGNO(10229) "Malformed FTP response '%s'", response);
|
||||||
|
+ *mb = '\0';
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
if (!apr_isdigit(response[0]) || !apr_isdigit(response[1]) ||
|
||||||
|
- !apr_isdigit(response[2]) || (response[3] != ' ' && response[3] != '-'))
|
||||||
|
+ !apr_isdigit(response[2]) || (response[3] != ' ' && response[3] != '-'))
|
||||||
|
status = 0;
|
||||||
|
else
|
||||||
|
status = 100 * response[0] + 10 * response[1] + response[2] - 111 * '0';
|
||||||
|
|
||||||
|
mb = apr_cpystrn(mb, response + 4, me - mb);
|
||||||
|
|
||||||
|
- if (response[3] == '-') {
|
||||||
|
+ if (response[3] == '-') { /* multi-line reply "123-foo\nbar\n123 baz" */
|
||||||
|
memcpy(buff, response, 3);
|
||||||
|
buff[3] = ' ';
|
||||||
|
do {
|
||||||
|
- if (APR_SUCCESS != (rv = ftp_string_read(ftp_ctrl, bb, response, sizeof(response), &eos))) {
|
||||||
|
+ if (APR_SUCCESS != (rv = ftp_string_read(ftp_ctrl, bb, response, sizeof(response), &eos, &nread))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
mb = apr_cpystrn(mb, response + (' ' == response[0] ? 1 : 4), me - mb);
|
||||||
|
--
|
||||||
|
1.8.3.1
|
||||||
|
|
||||||
16
httpd.spec
16
httpd.spec
@ -8,7 +8,7 @@
|
|||||||
Name: httpd
|
Name: httpd
|
||||||
Summary: Apache HTTP Server
|
Summary: Apache HTTP Server
|
||||||
Version: 2.4.34
|
Version: 2.4.34
|
||||||
Release: 16
|
Release: 17
|
||||||
License: ASL 2.0
|
License: ASL 2.0
|
||||||
URL: https://httpd.apache.org/
|
URL: https://httpd.apache.org/
|
||||||
Source0: https://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2
|
Source0: https://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2
|
||||||
@ -104,6 +104,14 @@ Patch6029: CVE-2019-10098.patch
|
|||||||
Patch6030: CVE-2019-0196.patch
|
Patch6030: CVE-2019-0196.patch
|
||||||
Patch6031: CVE-2019-0197.patch
|
Patch6031: CVE-2019-0197.patch
|
||||||
Patch6032: CVE-2019-10097.patch
|
Patch6032: CVE-2019-10097.patch
|
||||||
|
Patch6033: CVE-2019-9517_CVE-2019-10081_CVE-2019-10082-1.patch
|
||||||
|
Patch6034: CVE-2019-9517_CVE-2019-10081_CVE-2019-10082-2.patch
|
||||||
|
Patch6035: CVE-2019-9517_CVE-2019-10081_CVE-2019-10082-3.patch
|
||||||
|
Patch6036: CVE-2019-9517_CVE-2019-10081_CVE-2019-10082-4.patch
|
||||||
|
Patch6037: CVE-2019-9517_CVE-2019-10081_CVE-2019-10082-5.patch
|
||||||
|
Patch6038: CVE-2020-1927-1.patch
|
||||||
|
Patch6039: CVE-2020-1927-2.patch
|
||||||
|
Patch6040: CVE-2020-1934.patch
|
||||||
|
|
||||||
Patch9000: layout_add_openEuler.patch
|
Patch9000: layout_add_openEuler.patch
|
||||||
|
|
||||||
@ -542,6 +550,12 @@ exit $rv
|
|||||||
%{_rpmconfigdir}/macros.d/macros.httpd
|
%{_rpmconfigdir}/macros.d/macros.httpd
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Thu Apr 23 2020 openEuler Buildteam <buildteam@openeuler.org> - 2.4.34-17
|
||||||
|
- Type:cves
|
||||||
|
- ID:CVE-2019-9517 CVE-2019-10081 CVE-2019-10082 CVE-2020-1927 CVE-2020-1934
|
||||||
|
- SUG:restart
|
||||||
|
- DESC:fix CVE-2019-9517 CVE-2019-10081 CVE-2019-10082 CVE-2020-1927 CVE-2020-1934
|
||||||
|
|
||||||
* Wed Apr 15 2020 chenzhen <chenzhen44@huawei.com> - 2.4.34-16
|
* Wed Apr 15 2020 chenzhen <chenzhen44@huawei.com> - 2.4.34-16
|
||||||
- Type:cves
|
- Type:cves
|
||||||
- ID:CVE-2019-10092 CVE-2019-10097 CVE-2019-10098 CVE-2019-0196 CVE-2019-0197
|
- ID:CVE-2019-10092 CVE-2019-10097 CVE-2019-10098 CVE-2019-0196 CVE-2019-0197
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user