CVE-2020-9490 CVE-2020-11984 CVE-2020-11993

This commit is contained in:
yu_boyun 2020-09-27 14:58:52 +08:00
parent dca712da1d
commit 4a04bc7a5c
4 changed files with 2367 additions and 1 deletions

61
CVE-2020-11984.patch Normal file
View File

@ -0,0 +1,61 @@
From 0c543e3f5b3881d515d6235f152aacaaaf3aba72 Mon Sep 17 00:00:00 2001
From: Yann Ylavic <ylavic@apache.org>
Date: Fri, 24 Jul 2020 09:35:25 +0000
Subject: [PATCH] Merge r1880205, r1880214 from trunk:
mod_proxy_uwsgi: Error out on HTTP header larger than 16K
The uwsgi protocol does not let us serialize more than 16K of HTTP header,
so fail early with 500 if it happens.
Follow up to r1880205, APLOGNO().
Submitted by: ylavic
Reviewed by: ylavic, covener, icing
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1880251 13f79535-47bb-0310-9956-ffa450edef68
---
modules/proxy/mod_proxy_uwsgi.c | 13 ++++++++++---
1 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/modules/proxy/mod_proxy_uwsgi.c b/modules/proxy/mod_proxy_uwsgi.c
index 2ac2a95d2ef..0209ac4062e 100644
--- a/modules/proxy/mod_proxy_uwsgi.c
+++ b/modules/proxy/mod_proxy_uwsgi.c
@@ -136,7 +136,7 @@ static int uwsgi_send_headers(request_rec *r, proxy_conn_rec * conn)
int j;
apr_size_t headerlen = 4;
- apr_uint16_t pktsize, keylen, vallen;
+ apr_size_t pktsize, keylen, vallen;
const char *script_name;
const char *path_info;
const char *auth;
@@ -178,6 +178,15 @@ static int uwsgi_send_headers(request_rec *r, proxy_conn_rec * conn)
headerlen += 2 + strlen(env[j].key) + 2 + strlen(env[j].val);
}
+ pktsize = headerlen - 4;
+ if (pktsize > APR_UINT16_MAX) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10259)
+ "can't send headers to %s:%u: packet size too "
+ "large (%" APR_SIZE_T_FMT ")",
+ conn->hostname, conn->port, pktsize);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
ptr = buf = apr_palloc(r->pool, headerlen);
ptr += 4;
@@ -196,8 +205,6 @@ static int uwsgi_send_headers(request_rec *r, proxy_conn_rec * conn)
ptr += vallen;
}
- pktsize = headerlen - 4;
-
buf[0] = 0;
buf[1] = (apr_byte_t) (pktsize & 0xff);
buf[2] = (apr_byte_t) ((pktsize >> 8) & 0xff);

1902
CVE-2020-11993.patch Normal file

File diff suppressed because it is too large Load Diff

394
CVE-2020-9490.patch Normal file
View File

@ -0,0 +1,394 @@
From f1e4032670b82a84a469f6506de9052fd9df54f8 Mon Sep 17 00:00:00 2001
From: Stefan Eissing <icing@apache.org>
Date: Wed, 29 Jul 2020 12:15:58 +0000
Subject: [PATCH] *) mod_http2: remote support for abandoned http-wg draft
<https://datatracker.ietf.org/doc/draft-kazuho-h2-cache-digest/>.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1880395 13f79535-47bb-0310-9956-ffa450edef68
---
modules/http2/h2_push.c | 255 ++++---------------------------------
modules/http2/h2_push.h | 54 +++++---
2 files changed, 64 insertions(+), 245 deletions(-)
diff --git a/modules/http2/h2_push.c b/modules/http2/h2_push.c
index 60488cf..dc21e1e 100644
--- a/modules/http2/h2_push.c
+++ b/modules/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 {
@@ -617,38 +590,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 = diary->entries->nelts-1;
+ int lastidx;
+ /* Move an existing entry to the last place */
+ if (diary->entries->nelts <= 0)
+ return;
+
/* move entry[idx] to the end */
+ 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)
@@ -691,30 +674,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;
@@ -829,11 +794,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 (nelts > APR_UINT32_MAX) {
- /* should not happen */
- return APR_ENOTIMPL;
- }
N = ceil_power_of_2(nelts);
log2n = h2_log2(N);
@@ -895,166 +855,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/modules/http2/h2_push.h b/modules/http2/h2_push.h
index bc24e68..d061dd8 100644
--- a/modules/http2/h2_push.h
+++ b/modules/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__) */

View File

@ -8,7 +8,7 @@
Name: httpd Name: httpd
Summary: Apache HTTP Server Summary: Apache HTTP Server
Version: 2.4.43 Version: 2.4.43
Release: 3 Release: 4
License: ASL 2.0 License: ASL 2.0
URL: https://httpd.apache.org/ URL: https://httpd.apache.org/
Source0: https://archive.apache.org/dist/httpd/httpd-%{version}.tar.bz2 Source0: https://archive.apache.org/dist/httpd/httpd-%{version}.tar.bz2
@ -66,6 +66,9 @@ Patch12: httpd-2.4.34-sslprotdefault.patch
Patch13: httpd-2.4.34-enable-sslv3.patch Patch13: httpd-2.4.34-enable-sslv3.patch
Patch14: layout_add_openEuler.patch Patch14: layout_add_openEuler.patch
Patch15: httpd-2.4.43-lua-resume.patch Patch15: httpd-2.4.43-lua-resume.patch
Patch16: CVE-2020-11984.patch
Patch17: CVE-2020-11993.patch
Patch18: CVE-2020-9490.patch
BuildRequires: gcc autoconf pkgconfig findutils xmlto perl-interpreter perl-generators systemd-devel BuildRequires: gcc autoconf pkgconfig findutils xmlto perl-interpreter perl-generators systemd-devel
BuildRequires: zlib-devel libselinux-devel lua-devel brotli-devel BuildRequires: zlib-devel libselinux-devel lua-devel brotli-devel
@ -502,6 +505,12 @@ exit $rv
%{_rpmconfigdir}/macros.d/macros.httpd %{_rpmconfigdir}/macros.d/macros.httpd
%changelog %changelog
* Sun Sep 27 2020 yuboyun <yuboyun@huawei.com> - 2.4.43-4
- Type:cves
- ID:CVE-2020-9490 CVE-2020-11984 CVE-2020-11993
- SUG:restart
- DESC:fix CVE-2020-9490 CVE-2020-11984 CVE-2020-11993
* Sat Sep 5 2020 zhaowei<zhaowei23@huawei.com> - 2.4.43-3 * Sat Sep 5 2020 zhaowei<zhaowei23@huawei.com> - 2.4.43-3
- Type:enhancement - Type:enhancement
- ID:NA - ID:NA