Compare commits
No commits in common. "c9-beta" and "c8-stream-2.4" have entirely different histories.
c9-beta
...
c8-stream-
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1 @@
|
||||
SOURCES/mod_http2-2.0.26.tar.gz
|
||||
SOURCES/mod_http2-1.15.7.tar.gz
|
||||
|
@ -1 +1 @@
|
||||
cbfe42690c6a382da29ab728b1aa757af552acbc SOURCES/mod_http2-2.0.26.tar.gz
|
||||
6f52107e47548eee1c45c3fc7a7ca2245a115dd8 SOURCES/mod_http2-1.15.7.tar.gz
|
||||
|
119
SOURCES/mod_http2-1.15.7-CVE-2020-11993.patch
Normal file
119
SOURCES/mod_http2-1.15.7-CVE-2020-11993.patch
Normal file
@ -0,0 +1,119 @@
|
||||
diff --git a/mod_http2/h2_mplx.c b/mod_http2/h2_mplx.c
|
||||
index c3d590d..33ea45e 100644
|
||||
--- a/mod_http2/h2_mplx.c
|
||||
+++ b/mod_http2/h2_mplx.c
|
||||
@@ -56,7 +56,7 @@ typedef struct {
|
||||
apr_size_t count;
|
||||
} stream_iter_ctx;
|
||||
|
||||
-static apr_status_t mplx_be_happy(h2_mplx *m);
|
||||
+static apr_status_t mplx_be_happy(h2_mplx *m, h2_task *task);
|
||||
static apr_status_t mplx_be_annoyed(h2_mplx *m);
|
||||
|
||||
apr_status_t h2_mplx_child_init(apr_pool_t *pool, server_rec *s)
|
||||
@@ -526,10 +526,10 @@ static apr_status_t out_open(h2_mplx *m, int stream_id, h2_bucket_beam *beam)
|
||||
stream->output = beam;
|
||||
|
||||
if (APLOGctrace2(m->c)) {
|
||||
- h2_beam_log(beam, m->c, APLOG_TRACE2, "out_open");
|
||||
+ h2_beam_log(beam, stream->task->c, APLOG_TRACE2, "out_open");
|
||||
}
|
||||
else {
|
||||
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, stream->task->c,
|
||||
"h2_mplx(%s): out open", stream->task->id);
|
||||
}
|
||||
|
||||
@@ -579,10 +579,10 @@ static apr_status_t out_close(h2_mplx *m, h2_task *task)
|
||||
return APR_ECONNABORTED;
|
||||
}
|
||||
|
||||
- ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, m->c,
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, task->c,
|
||||
"h2_mplx(%s): close", task->id);
|
||||
status = h2_beam_close(task->output.beam);
|
||||
- h2_beam_log(task->output.beam, m->c, APLOG_TRACE2, "out_close");
|
||||
+ h2_beam_log(task->output.beam, task->c, APLOG_TRACE2, "out_close");
|
||||
output_consumed_signal(m, task);
|
||||
check_data_for(m, stream, 1);
|
||||
return status;
|
||||
@@ -782,18 +782,18 @@ static void task_done(h2_mplx *m, h2_task *task)
|
||||
{
|
||||
h2_stream *stream;
|
||||
|
||||
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, task->c,
|
||||
"h2_mplx(%ld): task(%s) done", m->id, task->id);
|
||||
out_close(m, task);
|
||||
|
||||
task->worker_done = 1;
|
||||
task->done_at = apr_time_now();
|
||||
- ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, task->c,
|
||||
"h2_mplx(%s): request done, %f ms elapsed", task->id,
|
||||
(task->done_at - task->started_at) / 1000.0);
|
||||
|
||||
if (task->c && !task->c->aborted && task->started_at > m->last_mood_change) {
|
||||
- mplx_be_happy(m);
|
||||
+ mplx_be_happy(m, task);
|
||||
}
|
||||
|
||||
ap_assert(task->done_done == 0);
|
||||
@@ -805,13 +805,13 @@ static void task_done(h2_mplx *m, h2_task *task)
|
||||
/* reset and schedule again */
|
||||
h2_task_redo(task);
|
||||
h2_iq_add(m->q, stream->id, NULL, NULL);
|
||||
- ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, m->c,
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, task->c,
|
||||
H2_STRM_MSG(stream, "redo, added to q"));
|
||||
}
|
||||
else {
|
||||
/* stream not cleaned up, stay around */
|
||||
task->done_done = 1;
|
||||
- ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, task->c,
|
||||
H2_STRM_MSG(stream, "task_done, stream open"));
|
||||
if (stream->input) {
|
||||
h2_beam_leave(stream->input);
|
||||
@@ -824,7 +824,7 @@ static void task_done(h2_mplx *m, h2_task *task)
|
||||
else if ((stream = h2_ihash_get(m->shold, task->stream_id)) != NULL) {
|
||||
/* stream is done, was just waiting for this. */
|
||||
task->done_done = 1;
|
||||
- ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, task->c,
|
||||
H2_STRM_MSG(stream, "task_done, in hold"));
|
||||
if (stream->input) {
|
||||
h2_beam_leave(stream->input);
|
||||
@@ -832,12 +832,12 @@ static void task_done(h2_mplx *m, h2_task *task)
|
||||
stream_joined(m, stream);
|
||||
}
|
||||
else if ((stream = h2_ihash_get(m->spurge, task->stream_id)) != NULL) {
|
||||
- ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, m->c,
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, task->c,
|
||||
H2_STRM_LOG(APLOGNO(03517), stream, "already in spurge"));
|
||||
ap_assert("stream should not be in spurge" == NULL);
|
||||
}
|
||||
else {
|
||||
- ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, m->c, APLOGNO(03518)
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, task->c, APLOGNO(03518)
|
||||
"h2_mplx(%s): task_done, stream not found",
|
||||
task->id);
|
||||
ap_assert("stream should still be available" == NULL);
|
||||
@@ -963,7 +963,7 @@ static apr_status_t unschedule_slow_tasks(h2_mplx *m)
|
||||
return rv;
|
||||
}
|
||||
|
||||
-static apr_status_t mplx_be_happy(h2_mplx *m)
|
||||
+static apr_status_t mplx_be_happy(h2_mplx *m, h2_task *task)
|
||||
{
|
||||
apr_time_t now;
|
||||
|
||||
@@ -975,7 +975,7 @@ static apr_status_t mplx_be_happy(h2_mplx *m)
|
||||
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,
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, task->c,
|
||||
"h2_mplx(%ld): mood update, increasing worker limit to %d",
|
||||
m->id, m->limit_active);
|
||||
}
|
391
SOURCES/mod_http2-1.15.7-CVE-2020-9490.patch
Normal file
391
SOURCES/mod_http2-1.15.7-CVE-2020-9490.patch
Normal file
@ -0,0 +1,391 @@
|
||||
From b8a8c5061eada0ce3339b24ba1d587134552bc0c Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Eissing <stefan.eissing@greenbytes.de>
|
||||
Date: Wed, 29 Jul 2020 14:41:38 +0200
|
||||
Subject: [PATCH] * Removing support for abandoned draft of http-wg regarding
|
||||
cache-digests.
|
||||
|
||||
---
|
||||
|
||||
diff --git a/mod_http2/h2_push.c b/mod_http2/h2_push.c
|
||||
index 4a70674..8ae0b49 100644
|
||||
--- a/mod_http2/h2_push.c
|
||||
+++ b/mod_http2/h2_push.c
|
||||
@@ -464,33 +464,6 @@ apr_array_header_t *h2_push_collect(apr_pool_t *p, const h2_request *req,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
-/*******************************************************************************
|
||||
- * push diary
|
||||
- *
|
||||
- * - The push diary keeps track of resources already PUSHed via HTTP/2 on this
|
||||
- * connection. It records a hash value from the absolute URL of the resource
|
||||
- * pushed.
|
||||
- * - Lacking openssl, it uses 'apr_hashfunc_default' for the value
|
||||
- * - with openssl, it uses SHA256 to calculate the hash value
|
||||
- * - whatever the method to generate the hash, the diary keeps a maximum of 64
|
||||
- * bits per hash, limiting the memory consumption to about
|
||||
- * H2PushDiarySize * 8
|
||||
- * bytes. Entries are sorted by most recently used and oldest entries are
|
||||
- * forgotten first.
|
||||
- * - Clients can initialize/replace the push diary by sending a 'Cache-Digest'
|
||||
- * header. Currently, this is the base64url encoded value of the cache digest
|
||||
- * as specified in https://datatracker.ietf.org/doc/draft-kazuho-h2-cache-digest/
|
||||
- * This draft can be expected to evolve and the definition of the header
|
||||
- * will be added there and refined.
|
||||
- * - The cache digest header is a Golomb Coded Set of hash values, but it may
|
||||
- * limit the amount of bits per hash value even further. For a good description
|
||||
- * of GCS, read here:
|
||||
- * http://giovanni.bajo.it/post/47119962313/golomb-coded-sets-smaller-than-bloom-filters
|
||||
- * - The means that the push diary might be initialized with hash values of much
|
||||
- * less than 64 bits, leading to more false positives, but smaller digest size.
|
||||
- ******************************************************************************/
|
||||
-
|
||||
-
|
||||
#define GCSLOG_LEVEL APLOG_TRACE1
|
||||
|
||||
typedef struct h2_push_diary_entry {
|
||||
@@ -618,38 +591,48 @@ static int h2_push_diary_find(h2_push_diary *diary, apr_uint64_t hash)
|
||||
return -1;
|
||||
}
|
||||
|
||||
-static h2_push_diary_entry *move_to_last(h2_push_diary *diary, apr_size_t idx)
|
||||
+static void move_to_last(h2_push_diary *diary, apr_size_t idx)
|
||||
{
|
||||
h2_push_diary_entry *entries = (h2_push_diary_entry*)diary->entries->elts;
|
||||
h2_push_diary_entry e;
|
||||
- apr_size_t lastidx = (apr_size_t)diary->entries->nelts;
|
||||
+ int lastidx;
|
||||
|
||||
+ /* Move an existing entry to the last place */
|
||||
+ if (diary->entries->nelts <= 0)
|
||||
+ return;
|
||||
+
|
||||
/* move entry[idx] to the end */
|
||||
- if (idx+1 < lastidx) {
|
||||
+ lastidx = diary->entries->nelts - 1;
|
||||
+ if (idx < lastidx) {
|
||||
e = entries[idx];
|
||||
- memmove(entries+idx, entries+idx+1, sizeof(e) * (lastidx - idx));
|
||||
+ memmove(entries+idx, entries+idx+1, sizeof(h2_push_diary_entry) * (lastidx - idx));
|
||||
entries[lastidx] = e;
|
||||
}
|
||||
- return &entries[lastidx];
|
||||
}
|
||||
|
||||
-static void h2_push_diary_append(h2_push_diary *diary, h2_push_diary_entry *e)
|
||||
+static void remove_first(h2_push_diary *diary)
|
||||
{
|
||||
- h2_push_diary_entry *ne;
|
||||
+ h2_push_diary_entry *entries = (h2_push_diary_entry*)diary->entries->elts;
|
||||
+ int lastidx;
|
||||
|
||||
- if (diary->entries->nelts < diary->N) {
|
||||
- /* append a new diary entry at the end */
|
||||
- APR_ARRAY_PUSH(diary->entries, h2_push_diary_entry) = *e;
|
||||
- ne = &APR_ARRAY_IDX(diary->entries, diary->entries->nelts-1, h2_push_diary_entry);
|
||||
+ /* move remaining entries to index 0 */
|
||||
+ lastidx = diary->entries->nelts - 1;
|
||||
+ if (lastidx > 0) {
|
||||
+ --diary->entries->nelts;
|
||||
+ memmove(entries, entries+1, sizeof(h2_push_diary_entry) * diary->entries->nelts);
|
||||
}
|
||||
- else {
|
||||
- /* replace content with new digest. keeps memory usage constant once diary is full */
|
||||
- ne = move_to_last(diary, 0);
|
||||
- *ne = *e;
|
||||
+}
|
||||
+
|
||||
+static void h2_push_diary_append(h2_push_diary *diary, h2_push_diary_entry *e)
|
||||
+{
|
||||
+ while (diary->entries->nelts >= diary->N) {
|
||||
+ remove_first(diary);
|
||||
}
|
||||
+ /* append a new diary entry at the end */
|
||||
+ APR_ARRAY_PUSH(diary->entries, h2_push_diary_entry) = *e;
|
||||
/* Intentional no APLOGNO */
|
||||
ap_log_perror(APLOG_MARK, GCSLOG_LEVEL, 0, diary->entries->pool,
|
||||
- "push_diary_append: %"APR_UINT64_T_HEX_FMT, ne->hash);
|
||||
+ "push_diary_append: %"APR_UINT64_T_HEX_FMT, e->hash);
|
||||
}
|
||||
|
||||
apr_array_header_t *h2_push_diary_update(h2_session *session, apr_array_header_t *pushes)
|
||||
@@ -692,30 +675,12 @@ apr_array_header_t *h2_push_collect_update(h2_stream *stream,
|
||||
const struct h2_request *req,
|
||||
const struct h2_headers *res)
|
||||
{
|
||||
- h2_session *session = stream->session;
|
||||
- const char *cache_digest = apr_table_get(req->headers, "Cache-Digest");
|
||||
apr_array_header_t *pushes;
|
||||
- apr_status_t status;
|
||||
|
||||
- if (cache_digest && session->push_diary) {
|
||||
- status = h2_push_diary_digest64_set(session->push_diary, req->authority,
|
||||
- cache_digest, stream->pool);
|
||||
- if (status != APR_SUCCESS) {
|
||||
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, session->c,
|
||||
- H2_SSSN_LOG(APLOGNO(03057), session,
|
||||
- "push diary set from Cache-Digest: %s"), cache_digest);
|
||||
- }
|
||||
- }
|
||||
pushes = h2_push_collect(stream->pool, req, stream->push_policy, res);
|
||||
return h2_push_diary_update(stream->session, pushes);
|
||||
}
|
||||
|
||||
-static apr_int32_t h2_log2inv(unsigned char log2)
|
||||
-{
|
||||
- return log2? (1 << log2) : 1;
|
||||
-}
|
||||
-
|
||||
-
|
||||
typedef struct {
|
||||
h2_push_diary *diary;
|
||||
unsigned char log2p;
|
||||
@@ -830,11 +795,6 @@ apr_status_t h2_push_diary_digest_get(h2_push_diary *diary, apr_pool_t *pool,
|
||||
apr_size_t hash_count;
|
||||
|
||||
nelts = diary->entries->nelts;
|
||||
-
|
||||
- if ((apr_uint32_t)nelts > APR_UINT32_MAX) {
|
||||
- /* should not happen */
|
||||
- return APR_ENOTIMPL;
|
||||
- }
|
||||
N = ceil_power_of_2(nelts);
|
||||
log2n = h2_log2(N);
|
||||
|
||||
@@ -896,166 +856,3 @@ apr_status_t h2_push_diary_digest_get(h2_push_diary *diary, apr_pool_t *pool,
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
-typedef struct {
|
||||
- h2_push_diary *diary;
|
||||
- apr_pool_t *pool;
|
||||
- unsigned char log2p;
|
||||
- const unsigned char *data;
|
||||
- apr_size_t datalen;
|
||||
- apr_size_t offset;
|
||||
- unsigned int bit;
|
||||
- apr_uint64_t last_val;
|
||||
-} gset_decoder;
|
||||
-
|
||||
-static int gset_decode_next_bit(gset_decoder *decoder)
|
||||
-{
|
||||
- if (++decoder->bit >= 8) {
|
||||
- if (++decoder->offset >= decoder->datalen) {
|
||||
- return -1;
|
||||
- }
|
||||
- decoder->bit = 0;
|
||||
- }
|
||||
- return (decoder->data[decoder->offset] & cbit_mask[decoder->bit])? 1 : 0;
|
||||
-}
|
||||
-
|
||||
-static apr_status_t gset_decode_next(gset_decoder *decoder, apr_uint64_t *phash)
|
||||
-{
|
||||
- apr_uint64_t flex = 0, fixed = 0, delta;
|
||||
- int i;
|
||||
-
|
||||
- /* read 1 bits until we encounter 0, then read log2n(diary-P) bits.
|
||||
- * On a malformed bit-string, this will not fail, but produce results
|
||||
- * which are pbly too large. Luckily, the diary will modulo the hash.
|
||||
- */
|
||||
- while (1) {
|
||||
- int bit = gset_decode_next_bit(decoder);
|
||||
- if (bit == -1) {
|
||||
- return APR_EINVAL;
|
||||
- }
|
||||
- if (!bit) {
|
||||
- break;
|
||||
- }
|
||||
- ++flex;
|
||||
- }
|
||||
-
|
||||
- for (i = 0; i < decoder->log2p; ++i) {
|
||||
- int bit = gset_decode_next_bit(decoder);
|
||||
- if (bit == -1) {
|
||||
- return APR_EINVAL;
|
||||
- }
|
||||
- fixed = (fixed << 1) | bit;
|
||||
- }
|
||||
-
|
||||
- delta = (flex << decoder->log2p) | fixed;
|
||||
- *phash = delta + decoder->last_val;
|
||||
- decoder->last_val = *phash;
|
||||
-
|
||||
- /* Intentional no APLOGNO */
|
||||
- ap_log_perror(APLOG_MARK, GCSLOG_LEVEL, 0, decoder->pool,
|
||||
- "h2_push_diary_digest_dec: val=%"APR_UINT64_T_HEX_FMT", delta=%"
|
||||
- APR_UINT64_T_HEX_FMT", flex=%d, fixed=%"APR_UINT64_T_HEX_FMT,
|
||||
- *phash, delta, (int)flex, fixed);
|
||||
-
|
||||
- return APR_SUCCESS;
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * Initialize the push diary by a cache digest as described in
|
||||
- * https://datatracker.ietf.org/doc/draft-kazuho-h2-cache-digest/
|
||||
- * .
|
||||
- * @param diary the diary to set the digest into
|
||||
- * @param data the binary cache digest
|
||||
- * @param len the length of the cache digest
|
||||
- * @return APR_EINVAL if digest was not successfully parsed
|
||||
- */
|
||||
-apr_status_t h2_push_diary_digest_set(h2_push_diary *diary, const char *authority,
|
||||
- const char *data, apr_size_t len)
|
||||
-{
|
||||
- gset_decoder decoder;
|
||||
- unsigned char log2n, log2p;
|
||||
- int N, i;
|
||||
- apr_pool_t *pool = diary->entries->pool;
|
||||
- h2_push_diary_entry e;
|
||||
- apr_status_t status = APR_SUCCESS;
|
||||
-
|
||||
- if (len < 2) {
|
||||
- /* at least this should be there */
|
||||
- return APR_EINVAL;
|
||||
- }
|
||||
- log2n = data[0];
|
||||
- log2p = data[1];
|
||||
- diary->mask_bits = log2n + log2p;
|
||||
- if (diary->mask_bits > 64) {
|
||||
- /* cannot handle */
|
||||
- return APR_ENOTIMPL;
|
||||
- }
|
||||
-
|
||||
- /* whatever is in the digest, it replaces the diary entries */
|
||||
- apr_array_clear(diary->entries);
|
||||
- if (!authority || !strcmp("*", authority)) {
|
||||
- diary->authority = NULL;
|
||||
- }
|
||||
- else if (!diary->authority || strcmp(diary->authority, authority)) {
|
||||
- diary->authority = apr_pstrdup(diary->entries->pool, authority);
|
||||
- }
|
||||
-
|
||||
- N = h2_log2inv(log2n + log2p);
|
||||
-
|
||||
- decoder.diary = diary;
|
||||
- decoder.pool = pool;
|
||||
- decoder.log2p = log2p;
|
||||
- decoder.data = (const unsigned char*)data;
|
||||
- decoder.datalen = len;
|
||||
- decoder.offset = 1;
|
||||
- decoder.bit = 8;
|
||||
- decoder.last_val = 0;
|
||||
-
|
||||
- diary->N = N;
|
||||
- /* Determine effective N we use for storage */
|
||||
- if (!N) {
|
||||
- /* a totally empty cache digest. someone tells us that she has no
|
||||
- * entries in the cache at all. Use our own preferences for N+mask
|
||||
- */
|
||||
- diary->N = diary->NMax;
|
||||
- return APR_SUCCESS;
|
||||
- }
|
||||
- else if (N > diary->NMax) {
|
||||
- /* Store not more than diary is configured to hold. We open us up
|
||||
- * to DOS attacks otherwise. */
|
||||
- diary->N = diary->NMax;
|
||||
- }
|
||||
-
|
||||
- /* Intentional no APLOGNO */
|
||||
- ap_log_perror(APLOG_MARK, GCSLOG_LEVEL, 0, pool,
|
||||
- "h2_push_diary_digest_set: N=%d, log2n=%d, "
|
||||
- "diary->mask_bits=%d, dec.log2p=%d",
|
||||
- (int)diary->N, (int)log2n, diary->mask_bits,
|
||||
- (int)decoder.log2p);
|
||||
-
|
||||
- for (i = 0; i < diary->N; ++i) {
|
||||
- if (gset_decode_next(&decoder, &e.hash) != APR_SUCCESS) {
|
||||
- /* the data may have less than N values */
|
||||
- break;
|
||||
- }
|
||||
- h2_push_diary_append(diary, &e);
|
||||
- }
|
||||
-
|
||||
- /* Intentional no APLOGNO */
|
||||
- ap_log_perror(APLOG_MARK, GCSLOG_LEVEL, 0, pool,
|
||||
- "h2_push_diary_digest_set: diary now with %d entries, mask_bits=%d",
|
||||
- (int)diary->entries->nelts, diary->mask_bits);
|
||||
- return status;
|
||||
-}
|
||||
-
|
||||
-apr_status_t h2_push_diary_digest64_set(h2_push_diary *diary, const char *authority,
|
||||
- const char *data64url, apr_pool_t *pool)
|
||||
-{
|
||||
- const char *data;
|
||||
- apr_size_t len = h2_util_base64url_decode(&data, data64url, pool);
|
||||
- /* Intentional no APLOGNO */
|
||||
- ap_log_perror(APLOG_MARK, GCSLOG_LEVEL, 0, pool,
|
||||
- "h2_push_diary_digest64_set: digest=%s, dlen=%d",
|
||||
- data64url, (int)len);
|
||||
- return h2_push_diary_digest_set(diary, authority, data, len);
|
||||
-}
|
||||
-
|
||||
diff --git a/mod_http2/h2_push.h b/mod_http2/h2_push.h
|
||||
index 0533853..5dc189f 100644
|
||||
--- a/mod_http2/h2_push.h
|
||||
+++ b/mod_http2/h2_push.h
|
||||
@@ -35,6 +35,44 @@ typedef enum {
|
||||
H2_PUSH_DIGEST_SHA256
|
||||
} h2_push_digest_type;
|
||||
|
||||
+/*******************************************************************************
|
||||
+ * push diary
|
||||
+ *
|
||||
+ * - The push diary keeps track of resources already PUSHed via HTTP/2 on this
|
||||
+ * connection. It records a hash value from the absolute URL of the resource
|
||||
+ * pushed.
|
||||
+ * - Lacking openssl,
|
||||
+ * - with openssl, it uses SHA256 to calculate the hash value, otherwise it
|
||||
+ * falls back to apr_hashfunc_default()
|
||||
+ * - whatever the method to generate the hash, the diary keeps a maximum of 64
|
||||
+ * bits per hash, limiting the memory consumption to about
|
||||
+ * H2PushDiarySize * 8
|
||||
+ * bytes. Entries are sorted by most recently used and oldest entries are
|
||||
+ * forgotten first.
|
||||
+ * - While useful by itself to avoid duplicated PUSHes on the same connection,
|
||||
+ * the original idea was that clients provided a 'Cache-Digest' header with
|
||||
+ * the values of *their own* cached resources. This was described in
|
||||
+ * <https://datatracker.ietf.org/doc/draft-kazuho-h2-cache-digest/>
|
||||
+ * and some subsequent revisions that tweaked values but kept the overall idea.
|
||||
+ * - The draft was abandoned by the IETF http-wg, as support from major clients,
|
||||
+ * e.g. browsers, was lacking for various reasons.
|
||||
+ * - For these reasons, mod_h2 abandoned its support for client supplied values
|
||||
+ * but keeps the diary. It seems to provide value for applications using PUSH,
|
||||
+ * is configurable in size and defaults to a very moderate amount of memory
|
||||
+ * used.
|
||||
+ * - The cache digest header is a Golomb Coded Set of hash values, but it may
|
||||
+ * limit the amount of bits per hash value even further. For a good description
|
||||
+ * of GCS, read here:
|
||||
+ * <http://giovanni.bajo.it/post/47119962313/golomb-coded-sets-smaller-than-bloom-filters>
|
||||
+ ******************************************************************************/
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * The push diary is based on the abandoned draft
|
||||
+ * <https://datatracker.ietf.org/doc/draft-kazuho-h2-cache-digest/>
|
||||
+ * that describes how to use golomb filters.
|
||||
+ */
|
||||
+
|
||||
typedef struct h2_push_diary h2_push_diary;
|
||||
|
||||
typedef void h2_push_digest_calc(h2_push_diary *diary, apr_uint64_t *phash, h2_push *push);
|
||||
@@ -101,20 +139,4 @@ apr_status_t h2_push_diary_digest_get(h2_push_diary *diary, apr_pool_t *p,
|
||||
int maxP, const char *authority,
|
||||
const char **pdata, apr_size_t *plen);
|
||||
|
||||
-/**
|
||||
- * Initialize the push diary by a cache digest as described in
|
||||
- * https://datatracker.ietf.org/doc/draft-kazuho-h2-cache-digest/
|
||||
- * .
|
||||
- * @param diary the diary to set the digest into
|
||||
- * @param authority the authority to set the data for
|
||||
- * @param data the binary cache digest
|
||||
- * @param len the length of the cache digest
|
||||
- * @return APR_EINVAL if digest was not successfully parsed
|
||||
- */
|
||||
-apr_status_t h2_push_diary_digest_set(h2_push_diary *diary, const char *authority,
|
||||
- const char *data, apr_size_t len);
|
||||
-
|
||||
-apr_status_t h2_push_diary_digest64_set(h2_push_diary *diary, const char *authority,
|
||||
- const char *data64url, apr_pool_t *pool);
|
||||
-
|
||||
#endif /* defined(__mod_h2__h2_push__) */
|
81
SOURCES/mod_http2-1.15.7-CVE-2021-33193.patch
Normal file
81
SOURCES/mod_http2-1.15.7-CVE-2021-33193.patch
Normal file
@ -0,0 +1,81 @@
|
||||
diff --git a/mod_http2/h2_request.c b/mod_http2/h2_request.c
|
||||
index 5893c8b..1131440 100644
|
||||
--- a/mod_http2/h2_request.c
|
||||
+++ b/mod_http2/h2_request.c
|
||||
@@ -206,75 +206,13 @@ h2_request *h2_request_clone(apr_pool_t *p, const h2_request *src)
|
||||
return dst;
|
||||
}
|
||||
|
||||
-#if !AP_MODULE_MAGIC_AT_LEAST(20150222, 13)
|
||||
-static request_rec *my_ap_create_request(conn_rec *c)
|
||||
-{
|
||||
- apr_pool_t *p;
|
||||
- request_rec *r;
|
||||
-
|
||||
- apr_pool_create(&p, c->pool);
|
||||
- apr_pool_tag(p, "request");
|
||||
- r = apr_pcalloc(p, sizeof(request_rec));
|
||||
- AP_READ_REQUEST_ENTRY((intptr_t)r, (uintptr_t)c);
|
||||
- r->pool = p;
|
||||
- r->connection = c;
|
||||
- r->server = c->base_server;
|
||||
-
|
||||
- r->user = NULL;
|
||||
- r->ap_auth_type = NULL;
|
||||
-
|
||||
- r->allowed_methods = ap_make_method_list(p, 2);
|
||||
-
|
||||
- r->headers_in = apr_table_make(r->pool, 5);
|
||||
- r->trailers_in = apr_table_make(r->pool, 5);
|
||||
- r->subprocess_env = apr_table_make(r->pool, 25);
|
||||
- r->headers_out = apr_table_make(r->pool, 12);
|
||||
- r->err_headers_out = apr_table_make(r->pool, 5);
|
||||
- r->trailers_out = apr_table_make(r->pool, 5);
|
||||
- r->notes = apr_table_make(r->pool, 5);
|
||||
-
|
||||
- r->request_config = ap_create_request_config(r->pool);
|
||||
- /* Must be set before we run create request hook */
|
||||
-
|
||||
- r->proto_output_filters = c->output_filters;
|
||||
- r->output_filters = r->proto_output_filters;
|
||||
- r->proto_input_filters = c->input_filters;
|
||||
- r->input_filters = r->proto_input_filters;
|
||||
- ap_run_create_request(r);
|
||||
- r->per_dir_config = r->server->lookup_defaults;
|
||||
-
|
||||
- r->sent_bodyct = 0; /* bytect isn't for body */
|
||||
-
|
||||
- r->read_length = 0;
|
||||
- r->read_body = REQUEST_NO_BODY;
|
||||
-
|
||||
- r->status = HTTP_OK; /* Until further notice */
|
||||
- r->header_only = 0;
|
||||
- r->the_request = NULL;
|
||||
-
|
||||
- /* Begin by presuming any module can make its own path_info assumptions,
|
||||
- * until some module interjects and changes the value.
|
||||
- */
|
||||
- r->used_path_info = AP_REQ_DEFAULT_PATH_INFO;
|
||||
-
|
||||
- r->useragent_addr = c->client_addr;
|
||||
- r->useragent_ip = c->client_ip;
|
||||
-
|
||||
- return r;
|
||||
-}
|
||||
-#endif
|
||||
-
|
||||
request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c)
|
||||
{
|
||||
- int access_status = HTTP_OK;
|
||||
+ int access_status = HTTP_OK;
|
||||
const char *rpath;
|
||||
const char *s;
|
||||
|
||||
-#if AP_MODULE_MAGIC_AT_LEAST(20150222, 13)
|
||||
request_rec *r = ap_create_request(c);
|
||||
-#else
|
||||
- request_rec *r = my_ap_create_request(c);
|
||||
-#endif
|
||||
|
||||
r->headers_in = apr_table_clone(r->pool, req->headers);
|
||||
|
13
SOURCES/mod_http2-1.15.7-CVE-2021-44224.patch
Normal file
13
SOURCES/mod_http2-1.15.7-CVE-2021-44224.patch
Normal file
@ -0,0 +1,13 @@
|
||||
diff --git a/mod_http2/h2_request.c b/mod_http2/h2_request.c
|
||||
index 1131440..89a0b47 100644
|
||||
--- a/mod_http2/h2_request.c
|
||||
+++ b/mod_http2/h2_request.c
|
||||
@@ -267,7 +267,7 @@ request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c)
|
||||
NULL, r, r->connection);
|
||||
|
||||
if (access_status != HTTP_OK
|
||||
- || (access_status = ap_run_post_read_request(r))) {
|
||||
+ || (access_status = ap_post_read_request(r))) {
|
||||
/* Request check post hooks failed. An example of this would be a
|
||||
* request for a vhost where h2 is disabled --> 421.
|
||||
*/
|
21
SOURCES/mod_http2-1.15.7-CVE-2023-25690.patch
Normal file
21
SOURCES/mod_http2-1.15.7-CVE-2023-25690.patch
Normal file
@ -0,0 +1,21 @@
|
||||
diff --git a/mod_http2/mod_proxy_http2.c b/mod_http2/mod_proxy_http2.c
|
||||
index 2208707..844653e 100644
|
||||
--- a/mod_http2/mod_proxy_http2.c
|
||||
+++ b/mod_http2/mod_proxy_http2.c
|
||||
@@ -159,6 +159,16 @@ static int proxy_http2_canon(request_rec *r, char *url)
|
||||
path = ap_proxy_canonenc(r->pool, url, (int)strlen(url),
|
||||
enc_path, 0, r->proxyreq);
|
||||
search = r->args;
|
||||
+ if (search && *(ap_scan_vchar_obstext(search))) {
|
||||
+ /*
|
||||
+ * We have a raw control character or a ' ' in r->args.
|
||||
+ * Correct encoding was missed.
|
||||
+ */
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10412)
|
||||
+ "To be forwarded query string contains control "
|
||||
+ "characters or spaces");
|
||||
+ return HTTP_FORBIDDEN;
|
||||
+ }
|
||||
}
|
||||
break;
|
||||
case PROXYREQ_PROXY:
|
217
SOURCES/mod_http2-1.15.7-CVE-2023-45802.patch
Normal file
217
SOURCES/mod_http2-1.15.7-CVE-2023-45802.patch
Normal file
@ -0,0 +1,217 @@
|
||||
diff --git a/mod_http2/h2_mplx.c b/mod_http2/h2_mplx.c
|
||||
index 33ea45e..f49b58e 100644
|
||||
--- a/mod_http2/h2_mplx.c
|
||||
+++ b/mod_http2/h2_mplx.c
|
||||
@@ -352,10 +352,11 @@ apr_status_t h2_mplx_stream_do(h2_mplx *m, h2_mplx_stream_cb *cb, void *ctx)
|
||||
{
|
||||
stream_iter_ctx_t x;
|
||||
|
||||
- H2_MPLX_ENTER(m);
|
||||
-
|
||||
x.cb = cb;
|
||||
x.ctx = ctx;
|
||||
+
|
||||
+ H2_MPLX_ENTER(m);
|
||||
+
|
||||
h2_ihash_iter(m->streams, stream_iter_wrap, &x);
|
||||
|
||||
H2_MPLX_LEAVE(m);
|
||||
@@ -1143,14 +1144,33 @@ int h2_mplx_awaits_data(h2_mplx *m)
|
||||
return waiting;
|
||||
}
|
||||
|
||||
-apr_status_t h2_mplx_client_rst(h2_mplx *m, int stream_id)
|
||||
+apr_status_t h2_mplx_client_rst(h2_mplx *m, int stream_id, h2_stream *stream)
|
||||
{
|
||||
- h2_stream *stream;
|
||||
apr_status_t status = APR_SUCCESS;
|
||||
-
|
||||
+ int registered;
|
||||
+
|
||||
H2_MPLX_ENTER_ALWAYS(m);
|
||||
- stream = h2_ihash_get(m->streams, stream_id);
|
||||
- if (stream && stream->task) {
|
||||
+ registered = (h2_ihash_get(m->streams, stream_id) != NULL);
|
||||
+
|
||||
+ if (!stream) {
|
||||
+ /* a RST might arrive so late, we have already forgotten
|
||||
+ * about it. Seems ok. */
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, m->c,
|
||||
+ H2_MPLX_MSG(m, "RST on unknown stream %d"), stream_id);
|
||||
+ AP_DEBUG_ASSERT(!registered);
|
||||
+ }
|
||||
+ else if (!registered) {
|
||||
+ /* a RST on a stream that mplx has not been told about, but
|
||||
+ * which the session knows. Very early and annoying. */
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, m->c,
|
||||
+ H2_STRM_MSG(stream, "very early RST, drop"));
|
||||
+ h2_stream_set_monitor(stream, NULL);
|
||||
+ h2_stream_rst(stream, H2_ERR_STREAM_CLOSED);
|
||||
+ h2_stream_dispatch(stream, H2_SEV_EOS_SENT);
|
||||
+ stream_cleanup(m, stream);
|
||||
+ mplx_be_annoyed(m);
|
||||
+ }
|
||||
+ else if (stream->task) {
|
||||
status = mplx_be_annoyed(m);
|
||||
}
|
||||
H2_MPLX_LEAVE(m);
|
||||
diff --git a/mod_http2/h2_mplx.h b/mod_http2/h2_mplx.h
|
||||
index 8a4f63f..6d838e5 100644
|
||||
--- a/mod_http2/h2_mplx.h
|
||||
+++ b/mod_http2/h2_mplx.h
|
||||
@@ -204,7 +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);
|
||||
+apr_status_t h2_mplx_client_rst(h2_mplx *m, int stream_id,
|
||||
+ struct h2_stream *stream);
|
||||
|
||||
/*******************************************************************************
|
||||
* Output handling of streams.
|
||||
@@ -287,6 +288,9 @@ APR_RING_INSERT_TAIL((b), ap__b, h2_mplx, link); \
|
||||
*/
|
||||
#define H2_MPLX_REMOVE(e) APR_RING_REMOVE((e), link)
|
||||
|
||||
+#define H2_MPLX_MSG(m, msg) \
|
||||
+ "h2_mplx(%lu): "msg, (unsigned long)m->id
|
||||
+
|
||||
/*******************************************************************************
|
||||
* h2_mplx DoS protection
|
||||
******************************************************************************/
|
||||
diff --git a/mod_http2/h2_proxy_session.c b/mod_http2/h2_proxy_session.c
|
||||
index 97a4a2a..8478b16 100644
|
||||
--- a/mod_http2/h2_proxy_session.c
|
||||
+++ b/mod_http2/h2_proxy_session.c
|
||||
@@ -677,7 +677,7 @@ static apr_status_t session_start(h2_proxy_session *session)
|
||||
apr_socket_t *s;
|
||||
|
||||
s = ap_get_conn_socket(session->c);
|
||||
-#if (!defined(WIN32) && !defined(NETWARE)) || defined(DOXYGEN)
|
||||
+#if !defined(WIN32) && !defined(NETWARE)
|
||||
if (s) {
|
||||
ap_sock_disable_nagle(s);
|
||||
}
|
||||
@@ -1515,9 +1515,20 @@ static int done_iter(void *udata, void *val)
|
||||
{
|
||||
cleanup_iter_ctx *ctx = udata;
|
||||
h2_proxy_stream *stream = val;
|
||||
- int touched = (stream->data_sent ||
|
||||
+ int touched = (stream->data_sent ||
|
||||
stream->id <= ctx->session->last_stream_id);
|
||||
- ctx->done(ctx->session, stream->r, APR_ECONNABORTED, touched);
|
||||
+
|
||||
+ if (touched && stream->output) {
|
||||
+ apr_bucket *b = ap_bucket_error_create(HTTP_BAD_GATEWAY, NULL,
|
||||
+ stream->r->pool,
|
||||
+ ctx->session->c->bucket_alloc);
|
||||
+ APR_BRIGADE_INSERT_TAIL(stream->output, b);
|
||||
+ b = apr_bucket_eos_create(ctx->session->c->bucket_alloc);
|
||||
+ APR_BRIGADE_INSERT_TAIL(stream->output, b);
|
||||
+ ap_pass_brigade(stream->r->output_filters, stream->output);
|
||||
+ }
|
||||
+ ctx->done(ctx->session, stream->r, APR_ECONNABORTED, touched);
|
||||
+
|
||||
return 1;
|
||||
}
|
||||
|
||||
diff --git a/mod_http2/h2_session.c b/mod_http2/h2_session.c
|
||||
index a5cc306..090bba6 100644
|
||||
--- a/mod_http2/h2_session.c
|
||||
+++ b/mod_http2/h2_session.c
|
||||
@@ -389,6 +389,10 @@ static int on_frame_recv_cb(nghttp2_session *ng2s,
|
||||
session->id, (int)frame->hd.stream_id,
|
||||
(int)frame->rst_stream.error_code);
|
||||
stream = get_stream(session, frame->hd.stream_id);
|
||||
+ if (stream) {
|
||||
+ rv = h2_stream_recv_frame(stream, NGHTTP2_RST_STREAM, frame->hd.flags,
|
||||
+ frame->hd.length + H2_FRAME_HDR_LEN);
|
||||
+ }
|
||||
if (stream && stream->initiated_on) {
|
||||
/* A stream reset on a request we sent it. Normal, when the
|
||||
* client does not want it. */
|
||||
@@ -397,7 +401,8 @@ static int on_frame_recv_cb(nghttp2_session *ng2s,
|
||||
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);
|
||||
+ h2_mplx_client_rst(session->mplx, frame->hd.stream_id,
|
||||
+ stream);
|
||||
++session->streams_reset;
|
||||
}
|
||||
break;
|
||||
@@ -778,6 +783,17 @@ static apr_status_t session_cleanup(h2_session *session, const char *trigger)
|
||||
"goodbye, clients will be confused, should not happen"));
|
||||
}
|
||||
|
||||
+ if (!h2_iq_empty(session->in_process)) {
|
||||
+ int sid;
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
|
||||
+ H2_SSSN_LOG(APLOGNO(), session,
|
||||
+ "cleanup, resetting %d streams in in_process"),
|
||||
+ h2_iq_count(session->in_process));
|
||||
+ while ((sid = h2_iq_shift(session->in_process)) > 0) {
|
||||
+ h2_mplx_client_rst(session->mplx, sid, get_stream(session, sid));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
transit(session, trigger, H2_SESSION_ST_CLEANUP);
|
||||
h2_mplx_release_and_join(session->mplx, session->iowait);
|
||||
session->mplx = NULL;
|
||||
diff --git a/mod_http2/h2_stream.c b/mod_http2/h2_stream.c
|
||||
index 6136baa..397f890 100644
|
||||
--- a/mod_http2/h2_stream.c
|
||||
+++ b/mod_http2/h2_stream.c
|
||||
@@ -120,7 +120,7 @@ static int trans_on_event[][H2_SS_MAX] = {
|
||||
{ S_XXX, S_ERR, S_ERR, S_CL_L, S_CLS, S_XXX, S_XXX, S_XXX, },/* EV_CLOSED_L*/
|
||||
{ S_ERR, S_ERR, S_ERR, S_CL_R, S_ERR, S_CLS, S_NOP, S_NOP, },/* EV_CLOSED_R*/
|
||||
{ S_CLS, S_CLS, S_CLS, S_CLS, S_CLS, S_CLS, S_NOP, S_NOP, },/* EV_CANCELLED*/
|
||||
-{ S_NOP, S_XXX, S_XXX, S_XXX, S_XXX, S_CLS, S_CLN, S_XXX, },/* EV_EOS_SENT*/
|
||||
+{ S_NOP, S_XXX, S_XXX, S_XXX, S_XXX, S_CLS, S_CLN, S_NOP, },/* EV_EOS_SENT*/
|
||||
};
|
||||
|
||||
static int on_map(h2_stream_state_t state, int map[H2_SS_MAX])
|
||||
diff --git a/mod_http2/mod_proxy_http2.c b/mod_http2/mod_proxy_http2.c
|
||||
index 844653e..b98298e 100644
|
||||
--- a/mod_http2/mod_proxy_http2.c
|
||||
+++ b/mod_http2/mod_proxy_http2.c
|
||||
@@ -67,7 +67,7 @@ typedef struct h2_proxy_ctx {
|
||||
unsigned flushall : 1;
|
||||
|
||||
request_rec *r; /* the request processed in this ctx */
|
||||
- apr_status_t r_status; /* status of request work */
|
||||
+ int r_status; /* status of request work */
|
||||
int r_done; /* request was processed, not necessarily successfully */
|
||||
int r_may_retry; /* request may be retried */
|
||||
h2_proxy_session *session; /* current http2 session against backend */
|
||||
@@ -403,7 +403,7 @@ run_connect:
|
||||
"setup new connection: is_ssl=%d %s %s %s",
|
||||
ctx->p_conn->is_ssl, ctx->p_conn->ssl_hostname,
|
||||
locurl, ctx->p_conn->hostname);
|
||||
- ctx->r_status = status;
|
||||
+ ctx->r_status = ap_map_http_request_error(status, HTTP_SERVICE_UNAVAILABLE);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -418,7 +418,7 @@ run_connect:
|
||||
if (ctx->master->aborted) goto cleanup;
|
||||
status = ctx_run(ctx);
|
||||
|
||||
- if (ctx->r_status != APR_SUCCESS && ctx->r_may_retry && !ctx->master->aborted) {
|
||||
+ if (ctx->r_status != OK && ctx->r_may_retry && !ctx->owner->aborted) {
|
||||
/* Not successfully processed, but may retry, tear down old conn and start over */
|
||||
if (ctx->p_conn) {
|
||||
ctx->p_conn->close = 1;
|
||||
@@ -453,6 +453,12 @@ cleanup:
|
||||
ap_set_module_config(ctx->owner->conn_config, &proxy_http2_module, NULL);
|
||||
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, ctx->owner,
|
||||
APLOGNO(03377) "leaving handler");
|
||||
+ if (ctx->r_status != OK) {
|
||||
+ ap_die(ctx->r_status, r);
|
||||
+ }
|
||||
+ else if (status != APR_SUCCESS) {
|
||||
+ ap_die(ap_map_http_request_error(status, HTTP_SERVICE_UNAVAILABLE), r);
|
||||
+ }
|
||||
return ctx->r_status;
|
||||
}
|
||||
|
@ -10,19 +10,16 @@ Subject: [PATCH] RESET stream after 100 failed incoming headers
|
||||
3 files changed, 9 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/mod_http2/h2_session.c b/mod_http2/h2_session.c
|
||||
index 1e560e47..6d379cc5 100644
|
||||
index a5cc306..4b38518 100644
|
||||
--- a/mod_http2/h2_session.c
|
||||
+++ b/mod_http2/h2_session.c
|
||||
@@ -319,9 +319,13 @@ static int on_header_cb(nghttp2_session *ngh2, const nghttp2_frame *frame,
|
||||
@@ -311,7 +311,12 @@ static int on_header_cb(nghttp2_session *ngh2, const nghttp2_frame *frame,
|
||||
|
||||
status = h2_stream_add_header(stream, (const char *)name, namelen,
|
||||
(const char *)value, valuelen);
|
||||
- if (status != APR_SUCCESS
|
||||
- && (!stream->rtmp
|
||||
- || stream->rtmp->http_status == H2_HTTP_STATUS_UNSET)) {
|
||||
+ if (status != APR_SUCCESS &&
|
||||
+ (!stream->rtmp ||
|
||||
+ stream->rtmp->http_status == H2_HTTP_STATUS_UNSET ||
|
||||
- if (status != APR_SUCCESS && !h2_stream_is_ready(stream)) {
|
||||
+ if (status != APR_SUCCESS
|
||||
+ && (!h2_stream_is_ready(stream) ||
|
||||
+ /* We accept a certain amount of failures in order to reply
|
||||
+ * with an informative HTTP error response like 413. But of the
|
||||
+ * client is too wrong, we fail the request an RESET the stream */
|
||||
@ -31,27 +28,28 @@ index 1e560e47..6d379cc5 100644
|
||||
}
|
||||
return 0;
|
||||
diff --git a/mod_http2/h2_stream.c b/mod_http2/h2_stream.c
|
||||
index f6c92024..ee87555f 100644
|
||||
index 6136baa..d3c4d99 100644
|
||||
--- a/mod_http2/h2_stream.c
|
||||
+++ b/mod_http2/h2_stream.c
|
||||
@@ -813,6 +813,7 @@ apr_status_t h2_stream_add_header(h2_stream *stream,
|
||||
@@ -733,6 +733,7 @@ apr_status_t h2_stream_add_header(h2_stream *stream,
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (error) {
|
||||
+ ++stream->request_headers_failed;
|
||||
set_error_response(stream, error);
|
||||
return APR_EINVAL;
|
||||
}
|
||||
diff --git a/mod_http2/h2_stream.h b/mod_http2/h2_stream.h
|
||||
index d68d4260..405978a4 100644
|
||||
index 79cb39d..4ddf1a2 100644
|
||||
--- a/mod_http2/h2_stream.h
|
||||
+++ b/mod_http2/h2_stream.h
|
||||
@@ -91,6 +91,7 @@ struct h2_stream {
|
||||
@@ -75,7 +75,8 @@ struct h2_stream {
|
||||
struct h2_request *rtmp; /* request being assembled */
|
||||
apr_table_t *trailers_in; /* optional, incoming trailers */
|
||||
apr_table_t *trailers; /* optional incoming trailers */
|
||||
int request_headers_added; /* number of request headers added */
|
||||
-
|
||||
+ int request_headers_failed; /* number of request headers failed to add */
|
||||
|
||||
#if AP_HAS_RESPONSE_BUCKETS
|
||||
ap_bucket_response *response; /* the final, non-interim response or NULL */
|
||||
|
||||
+
|
||||
struct h2_bucket_beam *input;
|
||||
apr_bucket_brigade *in_buffer;
|
||||
int in_window_size;
|
25
SOURCES/mod_http2-1.15.7-SNI.patch
Normal file
25
SOURCES/mod_http2-1.15.7-SNI.patch
Normal file
@ -0,0 +1,25 @@
|
||||
commit 0686f5d00a4b5a54238a1979f8e61d179adf2ea9
|
||||
Author: Tomas Korbar <tkorbar@redhat.com>
|
||||
Date: Thu Sep 22 14:56:24 2022 +0200
|
||||
|
||||
Backport refactor of SNI feature
|
||||
|
||||
diff --git a/mod_http2/mod_proxy_http2.c b/mod_http2/mod_proxy_http2.c
|
||||
index 83ae431..2208707 100644
|
||||
--- a/mod_http2/mod_proxy_http2.c
|
||||
+++ b/mod_http2/mod_proxy_http2.c
|
||||
@@ -403,14 +403,6 @@ run_connect:
|
||||
*/
|
||||
apr_table_setn(ctx->p_conn->connection->notes,
|
||||
"proxy-request-alpn-protos", "h2");
|
||||
- if (ctx->p_conn->ssl_hostname) {
|
||||
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctx->owner,
|
||||
- "set SNI to %s for (%s)",
|
||||
- ctx->p_conn->ssl_hostname,
|
||||
- ctx->p_conn->hostname);
|
||||
- apr_table_setn(ctx->p_conn->connection->notes,
|
||||
- "proxy-request-hostname", ctx->p_conn->ssl_hostname);
|
||||
- }
|
||||
}
|
||||
|
||||
if (ctx->master->aborted) goto cleanup;
|
271
SOURCES/mod_http2-1.15.7-log-error-resp.patch
Normal file
271
SOURCES/mod_http2-1.15.7-log-error-resp.patch
Normal file
@ -0,0 +1,271 @@
|
||||
diff --git a/mod_http2/h2.h b/mod_http2/h2.h
|
||||
index e057d66..33a225d 100644
|
||||
--- a/mod_http2/h2.h
|
||||
+++ b/mod_http2/h2.h
|
||||
@@ -141,8 +141,19 @@ struct h2_request {
|
||||
unsigned int chunked : 1; /* iff requst body needs to be forwarded as chunked */
|
||||
unsigned int serialize : 1; /* iff this request is written in HTTP/1.1 serialization */
|
||||
apr_off_t raw_bytes; /* RAW network bytes that generated this request - if known. */
|
||||
+ int http_status; /* Store a possible HTTP status code that gets
|
||||
+ * defined before creating the dummy HTTP/1.1
|
||||
+ * request e.g. due to an error already
|
||||
+ * detected.
|
||||
+ */
|
||||
};
|
||||
|
||||
+/*
|
||||
+ * A possible HTTP status code is not defined yet. See the http_status field
|
||||
+ * in struct h2_request above for further explanation.
|
||||
+ */
|
||||
+#define H2_HTTP_STATUS_UNSET (0)
|
||||
+
|
||||
typedef struct h2_headers h2_headers;
|
||||
|
||||
struct h2_headers {
|
||||
diff --git a/mod_http2/h2_request.c b/mod_http2/h2_request.c
|
||||
index 89a0b47..1892967 100644
|
||||
--- a/mod_http2/h2_request.c
|
||||
+++ b/mod_http2/h2_request.c
|
||||
@@ -79,11 +79,12 @@ apr_status_t h2_request_rcreate(h2_request **preq, apr_pool_t *pool,
|
||||
}
|
||||
|
||||
req = apr_pcalloc(pool, sizeof(*req));
|
||||
- req->method = apr_pstrdup(pool, r->method);
|
||||
- req->scheme = scheme;
|
||||
- req->authority = authority;
|
||||
- req->path = path;
|
||||
- req->headers = apr_table_make(pool, 10);
|
||||
+ req->method = apr_pstrdup(pool, r->method);
|
||||
+ req->scheme = scheme;
|
||||
+ req->authority = authority;
|
||||
+ req->path = path;
|
||||
+ req->headers = apr_table_make(pool, 10);
|
||||
+ req->http_status = H2_HTTP_STATUS_UNSET;
|
||||
if (r->server) {
|
||||
req->serialize = h2_config_rgeti(r, H2_CONF_SER_HEADERS);
|
||||
}
|
||||
@@ -208,53 +209,92 @@ h2_request *h2_request_clone(apr_pool_t *p, const h2_request *src)
|
||||
|
||||
request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c)
|
||||
{
|
||||
- int access_status = HTTP_OK;
|
||||
- const char *rpath;
|
||||
- const char *s;
|
||||
+ int access_status;
|
||||
|
||||
request_rec *r = ap_create_request(c);
|
||||
|
||||
- r->headers_in = apr_table_clone(r->pool, req->headers);
|
||||
-
|
||||
+#if AP_MODULE_MAGIC_AT_LEAST(20200331, 3)
|
||||
ap_run_pre_read_request(r, c);
|
||||
|
||||
/* Time to populate r with the data we have. */
|
||||
r->request_time = req->request_time;
|
||||
- r->method = apr_pstrdup(r->pool, req->method);
|
||||
- /* Provide quick information about the request method as soon as known */
|
||||
- r->method_number = ap_method_number_of(r->method);
|
||||
- if (r->method_number == M_GET && r->method[0] == 'H') {
|
||||
- r->header_only = 1;
|
||||
- }
|
||||
-
|
||||
- rpath = (req->path ? req->path : "");
|
||||
- ap_parse_uri(r, rpath);
|
||||
- r->protocol = (char*)"HTTP/2.0";
|
||||
- r->proto_num = HTTP_VERSION(2, 0);
|
||||
+ r->the_request = apr_psprintf(r->pool, "%s %s HTTP/2.0",
|
||||
+ req->method, req->path ? req->path : "");
|
||||
+ r->headers_in = apr_table_clone(r->pool, req->headers);
|
||||
|
||||
- r->the_request = apr_psprintf(r->pool, "%s %s %s",
|
||||
- r->method, rpath, r->protocol);
|
||||
-
|
||||
- /* update what we think the virtual host is based on the headers we've
|
||||
- * now read. may update status.
|
||||
- * Leave r->hostname empty, vhost will parse if form our Host: header,
|
||||
- * otherwise we get complains about port numbers.
|
||||
+ /* Start with r->hostname = NULL, ap_check_request_header() will get it
|
||||
+ * form Host: header, otherwise we get complains about port numbers.
|
||||
*/
|
||||
r->hostname = NULL;
|
||||
- ap_update_vhost_from_headers(r);
|
||||
-
|
||||
- /* we may have switched to another server */
|
||||
- r->per_dir_config = r->server->lookup_defaults;
|
||||
-
|
||||
- s = apr_table_get(r->headers_in, "Expect");
|
||||
- if (s && s[0]) {
|
||||
- if (ap_cstr_casecmp(s, "100-continue") == 0) {
|
||||
- r->expecting_100 = 1;
|
||||
+
|
||||
+ /* Validate HTTP/1 request and select vhost. */
|
||||
+ if (!ap_parse_request_line(r) || !ap_check_request_header(r)) {
|
||||
+ /* we may have switched to another server still */
|
||||
+ r->per_dir_config = r->server->lookup_defaults;
|
||||
+ if (req->http_status != H2_HTTP_STATUS_UNSET) {
|
||||
+ access_status = req->http_status;
|
||||
+ /* Be safe and close the connection */
|
||||
+ c->keepalive = AP_CONN_CLOSE;
|
||||
}
|
||||
else {
|
||||
- r->status = HTTP_EXPECTATION_FAILED;
|
||||
- ap_send_error_response(r, 0);
|
||||
+ access_status = r->status;
|
||||
}
|
||||
+ r->status = HTTP_OK;
|
||||
+ goto die;
|
||||
+ }
|
||||
+#else
|
||||
+ {
|
||||
+ const char *s;
|
||||
+
|
||||
+ r->headers_in = apr_table_clone(r->pool, req->headers);
|
||||
+ ap_run_pre_read_request(r, c);
|
||||
+
|
||||
+ /* Time to populate r with the data we have. */
|
||||
+ r->request_time = req->request_time;
|
||||
+ r->method = apr_pstrdup(r->pool, req->method);
|
||||
+ /* Provide quick information about the request method as soon as known */
|
||||
+ r->method_number = ap_method_number_of(r->method);
|
||||
+ if (r->method_number == M_GET && r->method[0] == 'H') {
|
||||
+ r->header_only = 1;
|
||||
+ }
|
||||
+ ap_parse_uri(r, req->path ? req->path : "");
|
||||
+ r->protocol = (char*)"HTTP/2.0";
|
||||
+ r->proto_num = HTTP_VERSION(2, 0);
|
||||
+ r->the_request = apr_psprintf(r->pool, "%s %s HTTP/2.0",
|
||||
+ r->method, req->path ? req->path : "");
|
||||
+
|
||||
+ /* Start with r->hostname = NULL, ap_check_request_header() will get it
|
||||
+ * form Host: header, otherwise we get complains about port numbers.
|
||||
+ */
|
||||
+ r->hostname = NULL;
|
||||
+ ap_update_vhost_from_headers(r);
|
||||
+
|
||||
+ /* we may have switched to another server */
|
||||
+ r->per_dir_config = r->server->lookup_defaults;
|
||||
+
|
||||
+ s = apr_table_get(r->headers_in, "Expect");
|
||||
+ if (s && s[0]) {
|
||||
+ if (ap_cstr_casecmp(s, "100-continue") == 0) {
|
||||
+ r->expecting_100 = 1;
|
||||
+ }
|
||||
+ else {
|
||||
+ r->status = HTTP_EXPECTATION_FAILED;
|
||||
+ access_status = r->status;
|
||||
+ goto die;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
+ /* we may have switched to another server */
|
||||
+ r->per_dir_config = r->server->lookup_defaults;
|
||||
+
|
||||
+ if (req->http_status != H2_HTTP_STATUS_UNSET) {
|
||||
+ access_status = req->http_status;
|
||||
+ r->status = HTTP_OK;
|
||||
+ /* Be safe and close the connection */
|
||||
+ c->keepalive = AP_CONN_CLOSE;
|
||||
+ goto die;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -266,28 +306,47 @@ request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c)
|
||||
ap_add_input_filter_handle(ap_http_input_filter_handle,
|
||||
NULL, r, r->connection);
|
||||
|
||||
- if (access_status != HTTP_OK
|
||||
- || (access_status = ap_post_read_request(r))) {
|
||||
+ if ((access_status = ap_run_post_read_request(r))) {
|
||||
/* Request check post hooks failed. An example of this would be a
|
||||
* request for a vhost where h2 is disabled --> 421.
|
||||
*/
|
||||
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(03367)
|
||||
"h2_request: access_status=%d, request_create failed",
|
||||
access_status);
|
||||
- ap_die(access_status, r);
|
||||
- ap_update_child_status(c->sbh, SERVER_BUSY_LOG, r);
|
||||
- ap_run_log_transaction(r);
|
||||
- r = NULL;
|
||||
- goto traceout;
|
||||
+ goto die;
|
||||
}
|
||||
|
||||
AP_READ_REQUEST_SUCCESS((uintptr_t)r, (char *)r->method,
|
||||
(char *)r->uri, (char *)r->server->defn_name,
|
||||
r->status);
|
||||
return r;
|
||||
-traceout:
|
||||
+die:
|
||||
+ ap_die(access_status, r);
|
||||
+
|
||||
+ /* ap_die() sent the response through the output filters, we must now
|
||||
+ * end the request with an EOR bucket for stream/pipeline accounting.
|
||||
+ */
|
||||
+ {
|
||||
+ apr_bucket_brigade *eor_bb;
|
||||
+#if AP_MODULE_MAGIC_AT_LEAST(20180905, 1)
|
||||
+ eor_bb = ap_acquire_brigade(c);
|
||||
+ APR_BRIGADE_INSERT_TAIL(eor_bb,
|
||||
+ ap_bucket_eor_create(c->bucket_alloc, r));
|
||||
+ ap_pass_brigade(c->output_filters, eor_bb);
|
||||
+ ap_release_brigade(c, eor_bb);
|
||||
+#else
|
||||
+ eor_bb = apr_brigade_create(c->pool, c->bucket_alloc);
|
||||
+ APR_BRIGADE_INSERT_TAIL(eor_bb,
|
||||
+ ap_bucket_eor_create(c->bucket_alloc, r));
|
||||
+ ap_pass_brigade(c->output_filters, eor_bb);
|
||||
+ apr_brigade_destroy(eor_bb);
|
||||
+#endif
|
||||
+ }
|
||||
+
|
||||
+ r = NULL;
|
||||
+
|
||||
AP_READ_REQUEST_FAILURE((uintptr_t)r);
|
||||
- return r;
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
|
||||
diff --git a/mod_http2/h2_session.c b/mod_http2/h2_session.c
|
||||
index 07983a3..2a97ad9 100644
|
||||
--- a/mod_http2/h2_session.c
|
||||
+++ b/mod_http2/h2_session.c
|
||||
@@ -311,9 +311,9 @@ static int on_header_cb(nghttp2_session *ngh2, const nghttp2_frame *frame,
|
||||
|
||||
status = h2_stream_add_header(stream, (const char *)name, namelen,
|
||||
(const char *)value, valuelen);
|
||||
- if (status != APR_SUCCESS
|
||||
- && (!h2_stream_is_ready(stream) ||
|
||||
- /* We accept a certain amount of failures in order to reply
|
||||
+ if (status != APR_SUCCESS &&
|
||||
+ (!stream->rtmp ||
|
||||
+ stream->rtmp->http_status == H2_HTTP_STATUS_UNSET || /* We accept a certain amount of failures in order to reply
|
||||
* with an informative HTTP error response like 413. But of the
|
||||
* client is too wrong, we fail the request an RESET the stream */
|
||||
stream->request_headers_failed > 100)) {
|
||||
diff --git a/mod_http2/h2_stream.c b/mod_http2/h2_stream.c
|
||||
index 62021b6..adbd5d2 100644
|
||||
--- a/mod_http2/h2_stream.c
|
||||
+++ b/mod_http2/h2_stream.c
|
||||
@@ -638,17 +638,8 @@ void h2_stream_set_request(h2_stream *stream, const h2_request *r)
|
||||
|
||||
static void set_error_response(h2_stream *stream, int http_status)
|
||||
{
|
||||
- if (!h2_stream_is_ready(stream)) {
|
||||
- conn_rec *c = stream->session->c;
|
||||
- apr_bucket *b;
|
||||
- h2_headers *response;
|
||||
-
|
||||
- response = h2_headers_die(http_status, stream->request, stream->pool);
|
||||
- prep_output(stream);
|
||||
- b = apr_bucket_eos_create(c->bucket_alloc);
|
||||
- APR_BRIGADE_INSERT_HEAD(stream->out_buffer, b);
|
||||
- b = h2_bucket_headers_create(c->bucket_alloc, response);
|
||||
- APR_BRIGADE_INSERT_HEAD(stream->out_buffer, b);
|
||||
+ if (!h2_stream_is_ready(stream) && stream->rtmp) {
|
||||
+ stream->rtmp->http_status = http_status;
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
--- a/mod_http2/h2_c2.c 2024/06/24 17:34:59 1918556
|
||||
+++ b/mod_http2/h2_c2.c 2024/06/24 17:51:42 1918557
|
||||
@@ -370,6 +370,13 @@
|
||||
h2_conn_ctx_t *conn_ctx = h2_conn_ctx_get(f->c);
|
||||
apr_status_t rv;
|
||||
|
||||
+ if (bb == NULL) {
|
||||
+#if !AP_MODULE_MAGIC_AT_LEAST(20180720, 1)
|
||||
+ f->c->data_in_output_filters = 0;
|
||||
+#endif
|
||||
+ return APR_SUCCESS;
|
||||
+ }
|
||||
+
|
||||
ap_assert(conn_ctx);
|
||||
#if AP_HAS_RESPONSE_BUCKETS
|
||||
if (!conn_ctx->has_final_response) {
|
||||
|
@ -2,43 +2,53 @@
|
||||
%{!?_httpd_mmn: %global _httpd_mmn %(cat %{_includedir}/httpd/.mmn 2>/dev/null || echo 0-0)}
|
||||
|
||||
Name: mod_http2
|
||||
Version: 2.0.26
|
||||
Release: 2%{?dist}.1
|
||||
Version: 1.15.7
|
||||
Release: 10%{?dist}.1
|
||||
Summary: module implementing HTTP/2 for Apache 2
|
||||
Group: System Environment/Daemons
|
||||
License: ASL 2.0
|
||||
URL: https://icing.github.io/mod_h2/
|
||||
Source0: https://github.com/icing/mod_h2/releases/download/v%{version}/mod_http2-%{version}.tar.gz
|
||||
# Patch1: ...
|
||||
|
||||
# Security patches:
|
||||
#
|
||||
Patch1: mod_http2-1.15.7-CVE-2020-9490.patch
|
||||
Patch2: mod_http2-1.15.7-CVE-2020-11993.patch
|
||||
Patch3: mod_http2-1.15.7-CVE-2021-33193.patch
|
||||
Patch4: mod_http2-1.15.7-CVE-2021-44224.patch
|
||||
Patch5: mod_http2-1.15.7-SNI.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2176209
|
||||
Patch6: mod_http2-1.15.7-CVE-2023-25690.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2243877
|
||||
Patch7: mod_http2-1.15.7-CVE-2023-45802.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2268277
|
||||
Patch100: mod_http2-2.0.26-CVE-2024-27316.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2295006
|
||||
Patch101: mod_http2-2.0.26-CVE-2024-36387.patch
|
||||
Patch8: mod_http2-1.15.7-CVE-2024-27316.patch
|
||||
# https://issues.redhat.com/browse/RHEL-46214
|
||||
Patch9: mod_http2-1.15.7-log-error-resp.patch
|
||||
|
||||
BuildRequires: make
|
||||
BuildRequires: gcc
|
||||
BuildRequires: pkgconfig, httpd-devel >= 2.4.20, libnghttp2-devel >= 1.7.0, openssl-devel >= 1.0.2
|
||||
BuildRequires: autoconf, libtool, /usr/bin/hostname
|
||||
Requires: httpd-mmn = %{_httpd_mmn}
|
||||
Requires: httpd >= 2.4.51-7
|
||||
Conflicts: httpd < 2.4.57
|
||||
Conflicts: httpd < 2.4.37-55
|
||||
|
||||
%description
|
||||
The mod_h2 Apache httpd module implements the HTTP2 protocol (h2+h2c) on
|
||||
top of libnghttp2 for httpd 2.4 servers.
|
||||
|
||||
%prep
|
||||
%autosetup -p1
|
||||
%setup -q
|
||||
%patch1 -p1 -b .CVE-2020-9490
|
||||
%patch2 -p1 -b .CVE-2020-11993
|
||||
%patch3 -p1 -b .CVE-2021-33193
|
||||
%patch4 -p1 -b .CVE-2021-44224
|
||||
%patch5 -p1 -b .SNI
|
||||
%patch6 -p1 -b .CVE-2023-25690
|
||||
%patch7 -p1 -b .CVE-2023-45802
|
||||
%patch8 -p1 -b .CVE-2024-27316
|
||||
%patch9 -p1 -b .log-error-resp
|
||||
|
||||
%build
|
||||
autoreconf -i
|
||||
%configure --with-apxs=%{_httpd_apxs}
|
||||
%make_build
|
||||
%configure
|
||||
make %{?_smp_mflags} V=1
|
||||
|
||||
%install
|
||||
%make_install
|
||||
make DESTDIR=%{buildroot} install
|
||||
rm -rf %{buildroot}/etc/httpd/share/doc/
|
||||
|
||||
# create configuration
|
||||
@ -46,8 +56,11 @@ mkdir -p %{buildroot}%{_httpd_modconfdir}
|
||||
echo "LoadModule http2_module modules/mod_http2.so" > %{buildroot}%{_httpd_modconfdir}/10-h2.conf
|
||||
echo "LoadModule proxy_http2_module modules/mod_proxy_http2.so" > %{buildroot}%{_httpd_modconfdir}/10-proxy_h2.conf
|
||||
|
||||
%check
|
||||
make check
|
||||
|
||||
%files
|
||||
%doc README.md ChangeLog AUTHORS
|
||||
%doc README README.md ChangeLog AUTHORS
|
||||
%license LICENSE
|
||||
%config(noreplace) %{_httpd_modconfdir}/10-h2.conf
|
||||
%config(noreplace) %{_httpd_modconfdir}/10-proxy_h2.conf
|
||||
@ -55,105 +68,72 @@ echo "LoadModule proxy_http2_module modules/mod_proxy_http2.so" > %{buildroot}%{
|
||||
%{_httpd_moddir}/mod_proxy_http2.so
|
||||
|
||||
%changelog
|
||||
* Tue Jul 09 2024 Luboš Uhliarik <luhliari@redhat.com> - 2.0.26-2.1
|
||||
- Resolves: RHEL-45806 - mod_http2: DoS by null pointer in websocket
|
||||
over HTTP/2 (CVE-2024-36387)
|
||||
* Tue Aug 27 2024 Luboš Uhliarik <luhliari@redhat.com> - 1.15.7-10.1
|
||||
- Resolves: RHEL-46214 - Access logs and ErrorDocument don't work when HTTP431
|
||||
occurs using http/2 on RHEL8
|
||||
|
||||
* Fri Apr 05 2024 Luboš Uhliarik <luhliari@redhat.com> - 2.0.26-2
|
||||
- Resolves: RHEL-31855 - mod_http2: httpd: CONTINUATION frames
|
||||
* Fri Apr 05 2024 Luboš Uhliarik <luhliari@redhat.com> - 1.15.7-10
|
||||
- Resolves: RHEL-29817 - httpd:2.4/mod_http2: httpd: CONTINUATION frames
|
||||
DoS (CVE-2024-27316)
|
||||
|
||||
* Thu Jan 18 2024 Luboš Uhliarik <luhliari@redhat.com> - 2.0.26-1
|
||||
- Resolves: RHEL-14691 - mod_http2 rebase to 2.0.26
|
||||
* Fri Feb 02 2024 Luboš Uhliarik <luhliari@redhat.com> - 1.15.7-9.3
|
||||
- Resolves: RHEL-13367 - httpd:2.4/mod_http2: reset requests exhaust memory
|
||||
(incomplete fix of CVE-2023-44487)(CVE-2023-45802)
|
||||
|
||||
* Wed Aug 16 2023 Luboš Uhliarik <luhliari@redhat.com> - 1.15.19-5
|
||||
- Resolves: #2177753 - CVE-2023-25690 httpd: HTTP request splitting with
|
||||
mod_rewrite and mod_proxy
|
||||
* Sat Mar 18 2023 Luboš Uhliarik <luhliari@redhat.com> - 1.15.7-8.3
|
||||
- Resolves: #2177748 - CVE-2023-25690 httpd:2.4/httpd: HTTP request splitting
|
||||
with mod_rewrite and mod_proxy
|
||||
|
||||
* Mon Dec 05 2022 Luboš Uhliarik <luhliari@redhat.com> - 1.15.19-4
|
||||
- Resolves: #2143176 - Dependency from mod_http2 on httpd broken
|
||||
* Thu Dec 08 2022 Luboš Uhliarik <luhliari@redhat.com> - 1.15.7-7
|
||||
- Resolves: #2095650 - Dependency from mod_http2 on httpd broken
|
||||
|
||||
* Mon Mar 21 2022 Luboš Uhliarik <luhliari@redhat.com> - 1.15.19-3
|
||||
- Resolves: #2066311 - CVE-2021-44224 httpd: possible NULL dereference or SSRF
|
||||
in forward proxy configurations
|
||||
* Tue Nov 01 2022 Tomas Korbar <tkorbar@redhat.com> - 1.15.7-6
|
||||
- Backport SNI feature refactor
|
||||
- Resolves: rhbz#2137257
|
||||
|
||||
* Mon Aug 09 2021 Mohan Boddu <mboddu@redhat.com> - 1.15.19-2
|
||||
- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags
|
||||
Related: rhbz#1991688
|
||||
* Mon Jan 24 2022 Luboš Uhliarik <luhliari@redhat.com> - 1.15.7-5
|
||||
- Resolves: #2035030 - CVE-2021-44224 httpd:2.4/httpd: possible NULL dereference
|
||||
or SSRF in forward proxy configurations
|
||||
|
||||
* Fri Jun 18 2021 Luboš Uhliarik <luhliari@redhat.com> - 1.15.19-1
|
||||
- new version 1.15.19
|
||||
- Resolves: #1970918 - mod_http2: rebase to 1.15.19
|
||||
* Thu Jan 06 2022 Luboš Uhliarik <luhliari@redhat.com> - 1.15.7-4
|
||||
- Resolves: #1966728 - CVE-2021-33193 httpd:2.4/mod_http2: httpd:
|
||||
Request splitting via HTTP/2 method injection and mod_proxy
|
||||
|
||||
* Wed Jun 16 2021 Mohan Boddu <mboddu@redhat.com> - 1.15.14-6
|
||||
- Rebuilt for RHEL 9 BETA for openssl 3.0
|
||||
Related: rhbz#1971065
|
||||
* Fri Oct 30 2020 Lubos Uhliarik <luhliari@redhat.com> - 1.15.7-3
|
||||
- Resolves: #1869077 - CVE-2020-11993 httpd:2.4/mod_http2: httpd:
|
||||
mod_http2 concurrent pool usage
|
||||
|
||||
* Fri May 7 2021 Joe Orton <jorton@redhat.com> - 1.15.14-5
|
||||
- avoid use of deprecated OpenSSL 3.0 API (#1958042)
|
||||
* Mon Aug 17 2020 Lubos Uhliarik <luhliari@redhat.com> - 1.15.7-2
|
||||
- Resolves: #1869073 - CVE-2020-9490 httpd:2.4/mod_http2: httpd:
|
||||
Push diary crash on specifically crafted HTTP/2 header
|
||||
|
||||
* Fri Apr 16 2021 Mohan Boddu <mboddu@redhat.com> - 1.15.14-4
|
||||
- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937
|
||||
* Tue Apr 14 2020 Lubos Uhliarik <luhliari@redhat.com> - 1.15.7-1
|
||||
- new version 1.15.7
|
||||
- Resolves: #1814236 - RFE: mod_http2 rebase
|
||||
- Resolves: #1747289 - CVE-2019-10082 httpd:2.4/mod_http2: httpd:
|
||||
read-after-free in h2 connection shutdown
|
||||
- Resolves: #1696099 - CVE-2019-0197 httpd:2.4/mod_http2: httpd:
|
||||
mod_http2: possible crash on late upgrade
|
||||
- Resolves: #1696094 - CVE-2019-0196 httpd:2.4/mod_http2: httpd:
|
||||
mod_http2: read-after-free on a string compare
|
||||
- Resolves: #1677591 - CVE-2018-17189 httpd:2.4/mod_http2: httpd:
|
||||
mod_http2: DoS via slow, unneeded request bodies
|
||||
|
||||
* Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 1.15.14-3
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
|
||||
* Thu Aug 29 2019 Lubos Uhliarik <luhliari@redhat.com> - 1.11.3-3
|
||||
- Resolves: #1744999 - CVE-2019-9511 httpd:2.4/mod_http2: HTTP/2: large amount
|
||||
of data request leads to denial of service
|
||||
- Resolves: #1745086 - CVE-2019-9516 httpd:2.4/mod_http2: HTTP/2: 0-length
|
||||
headers leads to denial of service
|
||||
- Resolves: #1745154 - CVE-2019-9517 httpd:2.4/mod_http2: HTTP/2: request for
|
||||
large response leads to denial of service
|
||||
|
||||
* Thu Aug 27 2020 Joe Orton <jorton@redhat.com> - 1.15.14-2
|
||||
- use apxs via _httpd_apxs macro
|
||||
* Thu Apr 4 2019 Joe Orton <jorton@redhat.com> - 1.11.3-2
|
||||
- update release (#1695587)
|
||||
|
||||
* Mon Aug 17 2020 Joe Orton <jorton@redhat.com> - 1.15.14-1
|
||||
- update to 1.15.14
|
||||
|
||||
* Tue Jul 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 1.15.7-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
|
||||
|
||||
* Fri Mar 6 2020 Joe Orton <jorton@redhat.com> - 1.15.7-1
|
||||
- update to 1.15.7
|
||||
|
||||
* Fri Feb 7 2020 Joe Orton <jorton@redhat.com> - 1.15.5-1
|
||||
- update to 1.15.5
|
||||
|
||||
* Wed Jan 29 2020 Fedora Release Engineering <releng@fedoraproject.org> - 1.15.3-3
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
|
||||
|
||||
* Mon Aug 19 2019 Lubos Uhliarik <luhliari@redhat.com> - 1.15.3-2
|
||||
- Rebuilt with newer nghttp2
|
||||
|
||||
* Thu Aug 8 2019 Joe Orton <jorton@redhat.com> - 1.15.3-1
|
||||
- update to 1.15.3
|
||||
|
||||
* Thu Jul 25 2019 Fedora Release Engineering <releng@fedoraproject.org> - 1.15.1-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
|
||||
|
||||
* Wed May 29 2019 Joe Orton <jorton@redhat.com> - 1.15.1-1
|
||||
- update to 1.15.1
|
||||
|
||||
* Wed May 22 2019 Joe Orton <jorton@redhat.com> - 1.15.0-1
|
||||
- update to 1.15.0
|
||||
|
||||
* Thu Mar 14 2019 Joe Orton <jorton@redhat.com> - 1.14.1-1
|
||||
- update to 1.14.1
|
||||
|
||||
* Tue Mar 5 2019 Joe Orton <jorton@redhat.com> - 1.14.0-1
|
||||
- update to 1.14.0
|
||||
|
||||
* Tue Feb 26 2019 Joe Orton <jorton@redhat.com> - 1.13.0-1
|
||||
- update to 1.13.0
|
||||
|
||||
* Fri Feb 01 2019 Fedora Release Engineering <releng@fedoraproject.org> - 1.12.1-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
|
||||
|
||||
* Fri Jan 18 2019 Joe Orton <jorton@redhat.com> - 1.12.1-1
|
||||
- update to 1.12.1
|
||||
|
||||
* Tue Oct 09 2018 Lubos Uhliarik <luhliari@redhat.com> - 1.11.2-1
|
||||
- new version 1.11.2
|
||||
|
||||
* Fri Oct 05 2018 Luboš Uhliarik <luhliari@redhat.com> - 1.11.1-1
|
||||
- new version 1.11.1 (CVE-2018-11763)
|
||||
|
||||
* Fri Jul 13 2018 Fedora Release Engineering <releng@fedoraproject.org> - 1.10.20-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
|
||||
* Tue Oct 16 2018 Lubos Uhliarik <luhliari@redhat.com> - 1.11.3-1
|
||||
- new version 1.11.3
|
||||
- Resolves: #1633401 - CVE-2018-11763 mod_http2: httpd: DoS for HTTP/2
|
||||
connections by continuous SETTINGS
|
||||
|
||||
* Wed May 2 2018 Joe Orton <jorton@redhat.com> - 1.10.20-1
|
||||
- update to 1.10.20
|
||||
|
Loading…
Reference in New Issue
Block a user