diff --git a/.gitignore b/.gitignore index 6e3f15e..cfbe234 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ +SOURCES/apache-poweredby.png SOURCES/httpd-2.4.37.tar.bz2 diff --git a/.httpd.metadata b/.httpd.metadata index e540f7e..06980e0 100644 --- a/.httpd.metadata +++ b/.httpd.metadata @@ -1 +1,2 @@ +3a7449d6cff00e5ccb3ed8571f34c0528555d38f SOURCES/apache-poweredby.png 4a38471de821288b0300148016f2b03dfee8adf2 SOURCES/httpd-2.4.37.tar.bz2 diff --git a/SOURCES/httpd-2.4.37-CVE-2021-26690.patch b/SOURCES/httpd-2.4.37-CVE-2021-26690.patch new file mode 100644 index 0000000..f606576 --- /dev/null +++ b/SOURCES/httpd-2.4.37-CVE-2021-26690.patch @@ -0,0 +1,14 @@ +diff --git a/modules/session/mod_session.c b/modules/session/mod_session.c +index 7ee477c..049255d 100644 +--- a/modules/session/mod_session.c ++++ b/modules/session/mod_session.c +@@ -404,8 +404,8 @@ static apr_status_t session_identity_decode(request_rec * r, session_rec * z) + char *plast = NULL; + const char *psep = "="; + char *key = apr_strtok(pair, psep, &plast); +- char *val = apr_strtok(NULL, psep, &plast); + if (key && *key) { ++ char *val = apr_strtok(NULL, sep, &plast); + if (!val || !*val) { + apr_table_unset(z->entries, key); + } diff --git a/SOURCES/httpd-2.4.37-CVE-2021-30641.patch b/SOURCES/httpd-2.4.37-CVE-2021-30641.patch new file mode 100644 index 0000000..5a34afb --- /dev/null +++ b/SOURCES/httpd-2.4.37-CVE-2021-30641.patch @@ -0,0 +1,44 @@ +diff --git a/server/request.c b/server/request.c +index d5c558a..18625af 100644 +--- a/server/request.c ++++ b/server/request.c +@@ -1419,7 +1419,20 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) + + cache = prep_walk_cache(AP_NOTE_LOCATION_WALK, r); + cached = (cache->cached != NULL); +- entry_uri = r->uri; ++ ++ /* ++ * When merge_slashes is set to AP_CORE_CONFIG_OFF the slashes in r->uri ++ * have not been merged. But for Location walks we always go with merged ++ * slashes no matter what merge_slashes is set to. ++ */ ++ if (sconf->merge_slashes != AP_CORE_CONFIG_OFF) { ++ entry_uri = r->uri; ++ } ++ else { ++ char *uri = apr_pstrdup(r->pool, r->uri); ++ ap_no2slash(uri); ++ entry_uri = uri; ++ } + + /* If we have an cache->cached location that matches r->uri, + * and the vhost's list of locations hasn't changed, we can skip +@@ -1486,7 +1499,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) + pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t)); + } + +- if (ap_regexec(entry_core->r, entry_uri, nmatch, pmatch, 0)) { ++ if (ap_regexec(entry_core->r, r->uri, nmatch, pmatch, 0)) { + continue; + } + +@@ -1496,7 +1509,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) + apr_table_setn(r->subprocess_env, + ((const char **)entry_core->refs->elts)[i], + apr_pstrndup(r->pool, +- entry_uri + pmatch[i].rm_so, ++ r->uri + pmatch[i].rm_so, + pmatch[i].rm_eo - pmatch[i].rm_so)); + } + } diff --git a/SOURCES/httpd-2.4.37-CVE-2021-44790.patch b/SOURCES/httpd-2.4.37-CVE-2021-44790.patch new file mode 100644 index 0000000..ddf4738 --- /dev/null +++ b/SOURCES/httpd-2.4.37-CVE-2021-44790.patch @@ -0,0 +1,10 @@ +--- a/modules/lua/lua_request.c 2021/12/16 11:09:40 1896038 ++++ b/modules/lua/lua_request.c 2021/12/16 11:15:47 1896039 +@@ -410,6 +410,7 @@ + if (end == NULL) break; + key = (char *) apr_pcalloc(r->pool, 256); + filename = (char *) apr_pcalloc(r->pool, 256); ++ if (end - crlf <= 8) break; + vlen = end - crlf - 8; + buffer = (char *) apr_pcalloc(r->pool, vlen+1); + memcpy(buffer, crlf + 4, vlen); diff --git a/SOURCES/httpd-2.4.37-proxy-ws-idle-timeout.patch b/SOURCES/httpd-2.4.37-proxy-ws-idle-timeout.patch index 25864bf..ef4408c 100644 --- a/SOURCES/httpd-2.4.37-proxy-ws-idle-timeout.patch +++ b/SOURCES/httpd-2.4.37-proxy-ws-idle-timeout.patch @@ -20,7 +20,7 @@ index 21ffbe2..16e1628 100644
  • Comments
  • +
    top
    -+

    ProxyWebsocketIdleTimeout

    ProxyWebsocketIdleTimeout Directive

    + + + diff --git a/SOURCES/httpd-2.4.37-r1845768+.patch b/SOURCES/httpd-2.4.37-r1845768+.patch new file mode 100644 index 0000000..a51934f --- /dev/null +++ b/SOURCES/httpd-2.4.37-r1845768+.patch @@ -0,0 +1,48 @@ +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index 70d151e..e4f5fc8 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -1095,7 +1095,9 @@ static apr_status_t ssl_init_ctx_crl(server_rec *s, + /* + * Read a file that optionally contains the server certificate in PEM + * format, possibly followed by a sequence of CA certificates that +- * should be sent to the peer in the SSL Certificate message. ++ * should be sent to the peer in the SSL Certificate message. Returns ++ * 0 on success, otherwise the OpenSSL error stack contents should be ++ * reported. + */ + static int use_certificate_chain( + SSL_CTX *ctx, char *file, int skipfirst, pem_password_cb *cb) +@@ -1128,8 +1130,10 @@ static int use_certificate_chain( + ctx->extra_certs = NULL; + } + #endif ++ + /* create new extra chain by loading the certs */ + n = 0; ++ ERR_clear_error(); + while ((x509 = PEM_read_bio_X509(bio, NULL, cb, NULL)) != NULL) { + if (!SSL_CTX_add_extra_chain_cert(ctx, x509)) { + X509_free(x509); +@@ -1190,6 +1194,7 @@ static apr_status_t ssl_init_ctx_cert_chain(server_rec *s, + if (n < 0) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01903) + "Failed to configure CA certificate chain!"); ++ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + return ssl_die(s); + } + +diff --git a/modules/ssl/ssl_util_ocsp.c b/modules/ssl/ssl_util_ocsp.c +index b11a6e9..b66e151 100644 +--- a/modules/ssl/ssl_util_ocsp.c ++++ b/modules/ssl/ssl_util_ocsp.c +@@ -363,7 +363,9 @@ static STACK_OF(X509) *modssl_read_ocsp_certificates(const char *file) + BIO_free(bio); + return NULL; + } ++ + /* create new extra chain by loading the certs */ ++ ERR_clear_error(); + while ((x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { + if (!other_certs) { + other_certs = sk_X509_new_null(); diff --git a/SOURCES/httpd-2.4.37-r1873907.patch b/SOURCES/httpd-2.4.37-r1873907.patch new file mode 100644 index 0000000..4ec0cfa --- /dev/null +++ b/SOURCES/httpd-2.4.37-r1873907.patch @@ -0,0 +1,265 @@ +diff --git a/docs/manual/mod/mod_ssl.html.en b/docs/manual/mod/mod_ssl.html.en +index b543150..ab72d4f 100644 +--- a/docs/manual/mod/mod_ssl.html.en ++++ b/docs/manual/mod/mod_ssl.html.en +@@ -1524,6 +1524,32 @@ The available (case-insensitive) protocols are:

    +

    Example

    SSLProtocol TLSv1
    +
    + ++
    ++

    SSLProtocol for name-based virtual hosts

    ++

    ++Before OpenSSL 1.1.1, even though the Server Name Indication (SNI) allowed to ++determine the targeted virtual host early in the TLS handshake, it was not ++possible to switch the TLS protocol version of the connection at this point, ++and thus the SSLProtocol negotiated was always based off ++the one of the base virtual host (first virtual host declared on the ++listening IP:port of the connection). ++

    ++

    ++Beginning with Apache HTTP server version 2.4.42, when built/linked against ++OpenSSL 1.1.1 or later, and when the SNI is provided by the client in the TLS ++handshake, the SSLProtocol of each (name-based) virtual ++host can and will be honored. ++

    ++

    ++For compatibility with previous versions, if no ++SSLProtocol is configured in a name-based virtual host, ++the one from the base virtual host still applies, unless ++SSLProtocol is configured globally in which case the ++global value applies (this latter exception is more sensible than compatible, ++though). ++

    ++
    ++ + +
    top
    +

    SSLProxyCACertificateFile Directive

    +diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c +index 0c4bf1f..ca5f702 100644 +--- a/modules/ssl/ssl_engine_config.c ++++ b/modules/ssl/ssl_engine_config.c +@@ -269,6 +269,7 @@ static void modssl_ctx_cfg_merge(apr_pool_t *p, + mrg->protocol_set = 1; + } + else { ++ mrg->protocol_set = base->protocol_set; + mrg->protocol = base->protocol; + } + +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index 31062bc..70d151e 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -520,7 +520,9 @@ static apr_status_t ssl_init_ctx_tls_extensions(server_rec *s, + "Configuring TLS extension handling"); + + /* +- * Server name indication (SNI) ++ * The Server Name Indication (SNI) provided by the ClientHello can be ++ * used to select the right (name-based-)vhost and its SSL configuration ++ * before the handshake takes place. + */ + if (!SSL_CTX_set_tlsext_servername_callback(mctx->ssl_ctx, + ssl_callback_ServerNameIndication) || +@@ -532,6 +534,16 @@ static apr_status_t ssl_init_ctx_tls_extensions(server_rec *s, + return ssl_die(s); + } + ++#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER) ++ /* ++ * The ClientHello callback also allows to retrieve the SNI, but since it ++ * runs at the earliest possible connection stage we can even set the TLS ++ * protocol version(s) according to the selected (name-based-)vhost, which ++ * is not possible at the SNI callback stage (due to OpenSSL internals). ++ */ ++ SSL_CTX_set_client_hello_cb(mctx->ssl_ctx, ssl_callback_ClientHello, NULL); ++#endif ++ + #ifdef HAVE_OCSP_STAPLING + /* + * OCSP Stapling support, status_request extension +@@ -708,7 +720,7 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + #else /* #if OPENSSL_VERSION_NUMBER < 0x10100000L */ + /* We first determine the maximum protocol version we should provide */ + #if SSL_HAVE_PROTOCOL_TLSV1_3 +- if (SSL_HAVE_PROTOCOL_TLSV1_3 && (protocol & SSL_PROTOCOL_TLSV1_3)) { ++ if (protocol & SSL_PROTOCOL_TLSV1_3) { + prot = TLS1_3_VERSION; + } else + #endif +diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c +index 8b44674..7313a55 100644 +--- a/modules/ssl/ssl_engine_kernel.c ++++ b/modules/ssl/ssl_engine_kernel.c +@@ -2357,28 +2357,31 @@ static apr_status_t set_challenge_creds(conn_rec *c, const char *servername, + * This function sets the virtual host from an extended + * client hello with a server name indication extension ("SNI", cf. RFC 6066). + */ +-static apr_status_t init_vhost(conn_rec *c, SSL *ssl) ++static apr_status_t init_vhost(conn_rec *c, SSL *ssl, const char *servername) + { +- const char *servername; + X509 *cert; + EVP_PKEY *key; + + if (c) { + SSLConnRec *sslcon = myConnConfig(c); +- +- if (sslcon->server != c->base_server) { +- /* already found the vhost */ +- return APR_SUCCESS; ++ ++ if (sslcon->vhost_found) { ++ /* already found the vhost? */ ++ return sslcon->vhost_found > 0 ? APR_SUCCESS : APR_NOTFOUND; + } ++ sslcon->vhost_found = -1; + +- servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); ++ if (!servername) { ++ servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); ++ } + if (servername) { + if (ap_vhost_iterate_given_conn(c, ssl_find_vhost, + (void *)servername)) { + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(02043) + "SSL virtual host for servername %s found", + servername); +- ++ ++ sslcon->vhost_found = +1; + return APR_SUCCESS; + } + else if (ssl_is_challenge(c, servername, &cert, &key)) { +@@ -2428,11 +2431,72 @@ static apr_status_t init_vhost(conn_rec *c, SSL *ssl) + int ssl_callback_ServerNameIndication(SSL *ssl, int *al, modssl_ctx_t *mctx) + { + conn_rec *c = (conn_rec *)SSL_get_app_data(ssl); +- apr_status_t status = init_vhost(c, ssl); ++ apr_status_t status = init_vhost(c, ssl, NULL); + + return (status == APR_SUCCESS)? SSL_TLSEXT_ERR_OK : SSL_TLSEXT_ERR_NOACK; + } + ++#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER) ++/* ++ * This callback function is called when the ClientHello is received. ++ */ ++int ssl_callback_ClientHello(SSL *ssl, int *al, void *arg) ++{ ++ char *servername = NULL; ++ conn_rec *c = (conn_rec *)SSL_get_app_data(ssl); ++ const unsigned char *pos; ++ size_t len, remaining; ++ (void)arg; ++ ++ /* We can't use SSL_get_servername() at this earliest OpenSSL connection ++ * stage, and there is no SSL_client_hello_get0_servername() provided as ++ * of OpenSSL 1.1.1. So the code below, that extracts the SNI from the ++ * ClientHello's TLS extensions, is taken from some test code in OpenSSL, ++ * i.e. client_hello_select_server_ctx() in "test/handshake_helper.c". ++ */ ++ ++ /* ++ * The server_name extension was given too much extensibility when it ++ * was written, so parsing the normal case is a bit complex. ++ */ ++ if (!SSL_client_hello_get0_ext(ssl, TLSEXT_TYPE_server_name, &pos, ++ &remaining) ++ || remaining <= 2) ++ goto give_up; ++ ++ /* Extract the length of the supplied list of names. */ ++ len = (*(pos++) << 8); ++ len += *(pos++); ++ if (len + 2 != remaining) ++ goto give_up; ++ remaining = len; ++ ++ /* ++ * The list in practice only has a single element, so we only consider ++ * the first one. ++ */ ++ if (remaining <= 3 || *pos++ != TLSEXT_NAMETYPE_host_name) ++ goto give_up; ++ remaining--; ++ ++ /* Now we can finally pull out the byte array with the actual hostname. */ ++ len = (*(pos++) << 8); ++ len += *(pos++); ++ if (len + 2 != remaining) ++ goto give_up; ++ ++ /* Use the SNI to switch to the relevant vhost, should it differ from ++ * c->base_server. ++ */ ++ servername = apr_pstrmemdup(c->pool, (const char *)pos, len); ++ ++give_up: ++ init_vhost(c, ssl, servername); ++ return SSL_CLIENT_HELLO_SUCCESS; ++} ++#endif /* OPENSSL_VERSION_NUMBER < 0x10101000L */ ++ ++ + /* + * Find a (name-based) SSL virtual host where either the ServerName + * or one of the ServerAliases matches the supplied name (to be used +@@ -2452,12 +2516,25 @@ static int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s) + if (found && (ssl = sslcon->ssl) && + (sc = mySrvConfig(s))) { + SSL_CTX *ctx = SSL_set_SSL_CTX(ssl, sc->server->ssl_ctx); ++ + /* + * SSL_set_SSL_CTX() only deals with the server cert, + * so we need to duplicate a few additional settings + * from the ctx by hand + */ + SSL_set_options(ssl, SSL_CTX_get_options(ctx)); ++#if OPENSSL_VERSION_NUMBER >= 0x10100000L \ ++ && (!defined(LIBRESSL_VERSION_NUMBER) \ ++ || LIBRESSL_VERSION_NUMBER >= 0x20800000L) ++ /* ++ * Don't switch the protocol if none is configured for this vhost, ++ * the default in this case is still the base server's SSLProtocol. ++ */ ++ if (myCtxConfig(sslcon, sc)->protocol_set) { ++ SSL_set_min_proto_version(ssl, SSL_CTX_get_min_proto_version(ctx)); ++ SSL_set_max_proto_version(ssl, SSL_CTX_get_max_proto_version(ctx)); ++ } ++#endif + if ((SSL_get_verify_mode(ssl) == SSL_VERIFY_NONE) || + (SSL_num_renegotiations(ssl) == 0)) { + /* +@@ -2654,7 +2731,7 @@ int ssl_callback_alpn_select(SSL *ssl, + * they callback the SNI. We need to make sure that we know which vhost + * we are dealing with so we respect the correct protocols. + */ +- init_vhost(c, ssl); ++ init_vhost(c, ssl, NULL); + + proposed = ap_select_protocol(c, NULL, sslconn->server, client_protos); + if (!proposed) { +diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h +index 8055200..f8a1db7 100644 +--- a/modules/ssl/ssl_private.h ++++ b/modules/ssl/ssl_private.h +@@ -563,6 +563,7 @@ typedef struct { + + const char *cipher_suite; /* cipher suite used in last reneg */ + int service_unavailable; /* thouugh we negotiate SSL, no requests will be served */ ++ int vhost_found; /* whether we found vhost from SNI already */ + } SSLConnRec; + + /* BIG FAT WARNING: SSLModConfigRec has unusual memory lifetime: it is +@@ -946,6 +947,9 @@ void ssl_callback_Info(const SSL *, int, int); + #ifdef HAVE_TLSEXT + int ssl_callback_ServerNameIndication(SSL *, int *, modssl_ctx_t *); + #endif ++#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER) ++int ssl_callback_ClientHello(SSL *, int *, void *); ++#endif + #ifdef HAVE_TLS_SESSION_TICKETS + int ssl_callback_SessionTicket(SSL *, unsigned char *, unsigned char *, + EVP_CIPHER_CTX *, HMAC_CTX *, int); diff --git a/SOURCES/httpd-2.4.37-reply-two-tls-rec.patch b/SOURCES/httpd-2.4.37-reply-two-tls-rec.patch new file mode 100644 index 0000000..a4a3835 --- /dev/null +++ b/SOURCES/httpd-2.4.37-reply-two-tls-rec.patch @@ -0,0 +1,188 @@ +diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c +index 018b667..4e3875a 100644 +--- a/modules/ssl/ssl_engine_io.c ++++ b/modules/ssl/ssl_engine_io.c +@@ -1598,18 +1598,32 @@ static apr_status_t ssl_io_filter_input(ap_filter_t *f, + } + + +-/* ssl_io_filter_output() produces one SSL/TLS message per bucket ++/* ssl_io_filter_output() produces one SSL/TLS record per bucket + * passed down the output filter stack. This results in a high +- * overhead (network packets) for any output comprising many small +- * buckets. SSI page applied through the HTTP chunk filter, for +- * example, may produce many brigades containing small buckets - +- * [chunk-size CRLF] [chunk-data] [CRLF]. ++ * overhead (more network packets & TLS processing) for any output ++ * comprising many small buckets. SSI output passed through the HTTP ++ * chunk filter, for example, may produce many brigades containing ++ * small buckets - [chunk-size CRLF] [chunk-data] [CRLF]. + * +- * The coalescing filter merges many small buckets into larger buckets +- * where possible, allowing the SSL I/O output filter to handle them +- * more efficiently. */ ++ * Sending HTTP response headers as a separate TLS record to the ++ * response body also reveals information to a network observer (the ++ * size of headers) which can be significant. ++ * ++ * The coalescing filter merges data buckets with the aim of producing ++ * fewer, larger TLS records - without copying/buffering all content ++ * and introducing unnecessary overhead. ++ * ++ * ### This buffering could be probably be done more comprehensively ++ * ### in ssl_io_filter_output itself. ++ * ++ * ### Another possible performance optimisation in particular for the ++ * ### [HEAP] [FILE] HTTP response case is using a brigade rather than ++ * ### a char array to buffer; using apr_brigade_write() to append ++ * ### will use already-allocated memory from the HEAP, reducing # of ++ * ### copies. ++ */ + +-#define COALESCE_BYTES (2048) ++#define COALESCE_BYTES (AP_IOBUFSIZE) + + struct coalesce_ctx { + char buffer[COALESCE_BYTES]; +@@ -1622,11 +1636,12 @@ static apr_status_t ssl_io_filter_coalesce(ap_filter_t *f, + apr_bucket *e, *upto; + apr_size_t bytes = 0; + struct coalesce_ctx *ctx = f->ctx; ++ apr_size_t buffered = ctx ? ctx->bytes : 0; /* space used on entry */ + unsigned count = 0; + + /* The brigade consists of zero-or-more small data buckets which +- * can be coalesced (the prefix), followed by the remainder of the +- * brigade. ++ * can be coalesced (referred to as the "prefix"), followed by the ++ * remainder of the brigade. + * + * Find the last bucket - if any - of that prefix. count gives + * the number of buckets in the prefix. The "prefix" must contain +@@ -1641,24 +1656,97 @@ static apr_status_t ssl_io_filter_coalesce(ap_filter_t *f, + e != APR_BRIGADE_SENTINEL(bb) + && !APR_BUCKET_IS_METADATA(e) + && e->length != (apr_size_t)-1 +- && e->length < COALESCE_BYTES +- && (bytes + e->length) < COALESCE_BYTES +- && (ctx == NULL +- || bytes + ctx->bytes + e->length < COALESCE_BYTES); ++ && e->length <= COALESCE_BYTES ++ && (buffered + bytes + e->length) <= COALESCE_BYTES; + e = APR_BUCKET_NEXT(e)) { + if (e->length) count++; /* don't count zero-length buckets */ + bytes += e->length; + } ++ ++ /* If there is room remaining and the next bucket is a data ++ * bucket, try to include it in the prefix to coalesce. For a ++ * typical [HEAP] [FILE] HTTP response brigade, this handles ++ * merging the headers and the start of the body into a single TLS ++ * record. */ ++ if (bytes + buffered > 0 ++ && bytes + buffered < COALESCE_BYTES ++ && e != APR_BRIGADE_SENTINEL(bb) ++ && !APR_BUCKET_IS_METADATA(e)) { ++ apr_status_t rv = APR_SUCCESS; ++ ++ /* For an indeterminate length bucket (PIPE/CGI/...), try a ++ * non-blocking read to have it morph into a HEAP. If the ++ * read fails with EAGAIN, it is harmless to try a split ++ * anyway, split is ENOTIMPL for most PIPE-like buckets. */ ++ if (e->length == (apr_size_t)-1) { ++ const char *discard; ++ apr_size_t ignore; ++ ++ rv = apr_bucket_read(e, &discard, &ignore, APR_NONBLOCK_READ); ++ if (rv != APR_SUCCESS && !APR_STATUS_IS_EAGAIN(rv)) { ++ ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, f->c, APLOGNO(10232) ++ "coalesce failed to read from %s bucket", ++ e->type->name); ++ return AP_FILTER_ERROR; ++ } ++ } ++ ++ if (rv == APR_SUCCESS) { ++ /* If the read above made the bucket morph, it may now fit ++ * entirely within the buffer. Otherwise, split it so it does ++ * fit. */ ++ if (e->length > COALESCE_BYTES ++ || e->length + buffered + bytes > COALESCE_BYTES) { ++ rv = apr_bucket_split(e, COALESCE_BYTES - (buffered + bytes)); ++ } ++ ++ if (rv == APR_SUCCESS && e->length == 0) { ++ /* As above, don't count in the prefix if the bucket is ++ * now zero-length. */ ++ } ++ else if (rv == APR_SUCCESS) { ++ ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, f->c, ++ "coalesce: adding %" APR_SIZE_T_FMT " bytes " ++ "from split %s bucket, total %" APR_SIZE_T_FMT, ++ e->length, e->type->name, bytes + buffered); ++ ++ count++; ++ bytes += e->length; ++ e = APR_BUCKET_NEXT(e); ++ } ++ else if (rv != APR_ENOTIMPL) { ++ ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, f->c, APLOGNO(10233) ++ "coalesce: failed to split data bucket"); ++ return AP_FILTER_ERROR; ++ } ++ } ++ } ++ ++ /* The prefix is zero or more buckets. upto now points to the ++ * bucket AFTER the end of the prefix, which may be the brigade ++ * sentinel. */ + upto = e; + +- /* Coalesce the prefix, if: +- * a) more than one bucket is found to coalesce, or +- * b) the brigade contains only a single data bucket, or +- * c) the data bucket is not last but we have buffered data already. ++ /* Coalesce the prefix, if any of the following are true: ++ * ++ * a) the prefix is more than one bucket ++ * OR ++ * b) the prefix is the entire brigade, which is a single bucket ++ * AND the prefix length is smaller than the buffer size, ++ * OR ++ * c) the prefix is a single bucket ++ * AND there is buffered data from a previous pass. ++ * ++ * The aim with (b) is to buffer a small bucket so it can be ++ * coalesced with future invocations of this filter. e.g. three ++ * calls each with a single 100 byte HEAP bucket should get ++ * coalesced together. But an invocation with a 8192 byte HEAP ++ * should pass through untouched. + */ + if (bytes > 0 + && (count > 1 +- || (upto == APR_BRIGADE_SENTINEL(bb)) ++ || (upto == APR_BRIGADE_SENTINEL(bb) ++ && bytes < COALESCE_BYTES) + || (ctx && ctx->bytes > 0))) { + /* If coalescing some bytes, ensure a context has been + * created. */ +@@ -1669,7 +1757,8 @@ static apr_status_t ssl_io_filter_coalesce(ap_filter_t *f, + + ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, f->c, + "coalesce: have %" APR_SIZE_T_FMT " bytes, " +- "adding %" APR_SIZE_T_FMT " more", ctx->bytes, bytes); ++ "adding %" APR_SIZE_T_FMT " more (buckets=%u)", ++ ctx->bytes, bytes, count); + + /* Iterate through the prefix segment. For non-fatal errors + * in this loop it is safe to break out and fall back to the +@@ -1684,7 +1773,8 @@ static apr_status_t ssl_io_filter_coalesce(ap_filter_t *f, + if (APR_BUCKET_IS_METADATA(e) + || e->length == (apr_size_t)-1) { + ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, f->c, APLOGNO(02012) +- "unexpected bucket type during coalesce"); ++ "unexpected %s bucket during coalesce", ++ e->type->name); + break; /* non-fatal error; break out */ + } + diff --git a/SOURCES/httpd-2.4.37-usertrack-samesite.patch b/SOURCES/httpd-2.4.37-usertrack-samesite.patch new file mode 100644 index 0000000..592616e --- /dev/null +++ b/SOURCES/httpd-2.4.37-usertrack-samesite.patch @@ -0,0 +1,178 @@ +diff --git a/docs/manual/mod/mod_usertrack.html.en b/docs/manual/mod/mod_usertrack.html.en +index b212747..d2da9b9 100644 +--- a/docs/manual/mod/mod_usertrack.html.en ++++ b/docs/manual/mod/mod_usertrack.html.en +@@ -47,7 +47,10 @@ + +@@ -127,6 +130,22 @@ CustomLog "logs/clickstream.log" usertrack +
    CookieExpires "3 weeks"
    + + ++
    ++
    top
    ++
    Description:Sets the maximum amount of time to wait for data on the websockets tunnel
    Syntax:ProxyWebsocketIdleTimeout num[ms]
    ++ ++ ++ ++ ++ ++ ++ ++
    Description:Adds the 'HTTPOnly' attribute to the cookie
    Syntax:CookieHTTPOnly on|off
    Default:CookieHTTPOnly off
    Context:server config, virtual host, directory, .htaccess
    Override:FileInfo
    Status:Extension
    Module:mod_usertrack
    ++

    When set to 'ON', the 'HTTPOnly' cookie attribute is added to this ++ modules tracking cookie. This attribute instructs browsers to block javascript ++ from reading the value of the cookie.

    ++ +

    +
    top
    +

    CookieName Directive

    +@@ -150,6 +169,45 @@ CustomLog "logs/clickstream.log" usertrack +
    CookieName clicktrack
    + + ++
    ++
    top
    ++

    CookieSameSite Directive

    ++ ++ ++ ++ ++ ++ ++ ++ ++
    Description:Adds the 'SameSite' attribute to the cookie
    Syntax:CookieSameSite None|Lax|Strict
    Default:unset
    Context:server config, virtual host, directory, .htaccess
    Override:FileInfo
    Status:Extension
    Module:mod_usertrack
    ++

    When set to 'None', 'Lax', or 'Strict', the 'SameSite' cookie attribute ++ is added to this modules tracking cookie with the corresponding value. ++ This attribute instructs browser on how to treat the cookie when it is ++ requested in a cross-site context.

    ++ ++
    ++

    A value of 'None' sets 'SameSite=None', which is the most liberal setting. To ++ omit this attribute, omit the directive entirely.

    ++
    ++ ++ ++
    ++
    top
    ++

    CookieSecure Directive

    ++ ++ ++ ++ ++ ++ ++ ++ ++
    Description:Adds the 'Secure' attribute to the cookie
    Syntax:CookieSecure on|off
    Default:CookieSecure off
    Context:server config, virtual host, directory, .htaccess
    Override:FileInfo
    Status:Extension
    Module:mod_usertrack
    ++

    When set to 'ON', the 'Secure' cookie attribute is added to this ++ modules tracking cookie. This attribute instructs browsers to only ++ transmit the cookie over HTTPS.

    ++ +
    +
    top
    +

    CookieStyle Directive

    +diff --git a/modules/metadata/mod_usertrack.c b/modules/metadata/mod_usertrack.c +index 73a9f45..65759c2 100644 +--- a/modules/metadata/mod_usertrack.c ++++ b/modules/metadata/mod_usertrack.c +@@ -86,6 +86,9 @@ typedef struct { + const char *cookie_domain; + char *regexp_string; /* used to compile regexp; save for debugging */ + ap_regex_t *regexp; /* used to find usertrack cookie in cookie header */ ++ int is_secure; ++ int is_httponly; ++ const char *samesite; + } cookie_dir_rec; + + /* Make Cookie: Now we have to generate something that is going to be +@@ -143,6 +146,21 @@ static void make_cookie(request_rec *r) + : ""), + NULL); + } ++ if (dcfg->samesite != NULL) { ++ new_cookie = apr_pstrcat(r->pool, new_cookie, "; ", ++ dcfg->samesite, ++ NULL); ++ } ++ if (dcfg->is_secure) { ++ new_cookie = apr_pstrcat(r->pool, new_cookie, "; Secure", ++ NULL); ++ } ++ if (dcfg->is_httponly) { ++ new_cookie = apr_pstrcat(r->pool, new_cookie, "; HttpOnly", ++ NULL); ++ } ++ ++ + + apr_table_addn(r->err_headers_out, + (dcfg->style == CT_COOKIE2 ? "Set-Cookie2" : "Set-Cookie"), +@@ -269,6 +287,7 @@ static void *make_cookie_dir(apr_pool_t *p, char *d) + dcfg->cookie_domain = NULL; + dcfg->style = CT_UNSET; + dcfg->enabled = 0; ++ /* calloc'ed to disabled: samesite, is_secure, is_httponly */ + + /* In case the user does not use the CookieName directive, + * we need to compile the regexp for the default cookie name. */ +@@ -429,6 +448,31 @@ static const char *set_cookie_style(cmd_parms *cmd, void *mconfig, + return NULL; + } + ++/* ++ * SameSite enabled disabled ++ */ ++ ++static const char *set_samesite_value(cmd_parms *cmd, void *mconfig, ++ const char *name) ++{ ++ cookie_dir_rec *dcfg; ++ ++ dcfg = (cookie_dir_rec *) mconfig; ++ ++ if (strcasecmp(name, "strict") == 0) { ++ dcfg->samesite = "SameSite=Strict"; ++ } else if (strcasecmp(name, "lax") == 0) { ++ dcfg->samesite = "SameSite=Lax"; ++ } else if (strcasecmp(name, "none") == 0) { ++ dcfg->samesite = "SameSite=None"; ++ } else { ++ return "CookieSameSite accepts 'Strict', 'Lax', or 'None'"; ++ } ++ ++ ++ return NULL; ++} ++ + static const command_rec cookie_log_cmds[] = { + AP_INIT_TAKE1("CookieExpires", set_cookie_exp, NULL, OR_FILEINFO, + "an expiry date code"), +@@ -440,6 +484,17 @@ static const command_rec cookie_log_cmds[] = { + "whether or not to enable cookies"), + AP_INIT_TAKE1("CookieName", set_cookie_name, NULL, OR_FILEINFO, + "name of the tracking cookie"), ++ AP_INIT_FLAG("CookieTracking", set_cookie_enable, NULL, OR_FILEINFO, ++ "whether or not to enable cookies"), ++ AP_INIT_TAKE1("CookieSameSite", set_samesite_value, NULL, OR_FILEINFO, ++ "SameSite setting"), ++ AP_INIT_FLAG("CookieSecure", ap_set_flag_slot, ++ (void *)APR_OFFSETOF(cookie_dir_rec, is_secure), OR_FILEINFO, ++ "is cookie secure"), ++ AP_INIT_FLAG("CookieHttpOnly", ap_set_flag_slot, ++ (void *)APR_OFFSETOF(cookie_dir_rec, is_httponly),OR_FILEINFO, ++ "is cookie http only"), ++ + {NULL} + }; + diff --git a/SOURCES/welcome.conf b/SOURCES/welcome.conf index 5158e8b..37b7394 100644 --- a/SOURCES/welcome.conf +++ b/SOURCES/welcome.conf @@ -16,4 +16,4 @@ Alias /.noindex.html /usr/share/httpd/noindex/index.html -Alias /poweredby.png /usr/share/httpd/icons/apache_pb2.png \ No newline at end of file +Alias /poweredby.png /usr/share/httpd/icons/apache_pb3.png \ No newline at end of file diff --git a/SPECS/httpd.spec b/SPECS/httpd.spec index f0189f7..2d766e0 100644 --- a/SPECS/httpd.spec +++ b/SPECS/httpd.spec @@ -13,7 +13,7 @@ Summary: Apache HTTP Server Name: httpd Version: 2.4.37 -Release: 39%{?dist}.2 +Release: 43%{?dist}.1 URL: https://httpd.apache.org/ Source0: https://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2 Source2: httpd.logrotate @@ -54,6 +54,7 @@ Source42: httpd-init.service Source43: httpd-ssl-gencerts Source44: httpd@.service Source45: config.layout +Source46: apache-poweredby.png # build/scripts patches # http://bugzilla.redhat.com/show_bug.cgi?id=1231924 @@ -101,6 +102,8 @@ Patch38: httpd-2.4.37-pr37355.patch Patch39: httpd-2.4.37-proxy-ws-idle-timeout.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1883648 Patch40: httpd-2.4.37-ssl-proxy-chains.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1935742 +Patch41: httpd-2.4.37-usertrack-samesite.patch # Bug fixes # https://bugzilla.redhat.com/show_bug.cgi?id=1397243 @@ -150,6 +153,12 @@ Patch83: httpd-2.4.37-r1878890.patch Patch84: httpd-2.4.37-r1878280.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1891594 Patch85: httpd-2.4.37-htcacheclean-dont-break.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1937334 +Patch86: httpd-2.4.37-r1873907.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1680111 +Patch87: httpd-2.4.37-reply-two-tls-rec.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1905613 +Patch88: httpd-2.4.37-r1845768+.patch # Security fixes Patch200: httpd-2.4.37-r1851471.patch @@ -179,10 +188,16 @@ Patch209: httpd-2.4.37-CVE-2020-1934.patch Patch210: httpd-2.4.37-CVE-2018-17199.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1866563 Patch211: httpd-2.4.37-CVE-2020-11984.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1972500 +Patch212: httpd-2.4.37-CVE-2021-30641.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1968307 +Patch213: httpd-2.4.37-CVE-2021-26690.patch # https://bugzilla.redhat.com/show_bug.cgi?id=2005117 -Patch212: httpd-2.4.37-CVE-2021-40438.patch +Patch214: httpd-2.4.37-CVE-2021-40438.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1966732 -Patch213: httpd-2.4.37-CVE-2021-26691.patch +Patch215: httpd-2.4.37-CVE-2021-26691.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2034674 +Patch216: httpd-2.4.37-CVE-2021-44790.patch License: ASL 2.0 Group: System Environment/Daemons @@ -192,7 +207,8 @@ BuildRequires: zlib-devel, libselinux-devel, lua-devel, brotli-devel BuildRequires: apr-devel >= 1.5.0, apr-util-devel >= 1.5.0, pcre-devel >= 5.0 BuildRequires: systemd-devel # web server testpage added to redhat-logos in 82.0 (rhbz1896319) -Requires: /etc/mime.types, system-logos-httpd >= 82.0 +# new logo requires new footer copyring which was added in rhbz1934800 +Requires: /etc/mime.types, system-logos(httpd-logo-ng) Obsoletes: httpd-suexec Provides: webserver Provides: mod_dav = %{version}-%{release}, httpd-suexec = %{version}-%{release} @@ -332,6 +348,7 @@ interface for storing and accessing per-user session data. %patch38 -p1 -b .pr37355 %patch39 -p1 -b .proxy-ws-idle-timeout %patch40 -p1 -b .ssl-proxy-chains +%patch41 -p1 -b .usertrack-samesite %patch61 -p1 -b .r1738878 %patch62 -p1 -b .r1633085 @@ -356,6 +373,9 @@ interface for storing and accessing per-user session data. %patch83 -p1 -b .r1878890 %patch84 -p1 -b .r1878280 %patch85 -p1 -b .htcacheclean-dont-break +%patch86 -p1 -b .r1873907 +%patch87 -p1 -b .reply-two-tls-rec +%patch88 -p1 -b .r1845768+ %patch200 -p1 -b .r1851471 %patch201 -p1 -b .CVE-2019-0211 @@ -369,8 +389,11 @@ interface for storing and accessing per-user session data. %patch209 -p1 -b .CVE-2020-1934 %patch210 -p1 -b .CVE-2018-17199 %patch211 -p1 -b .CVE-2020-11984 -%patch212 -p1 -b .CVE-2021-40438 -%patch213 -p1 -b .CVE-2021-26691 +%patch212 -p1 -b .CVE-2021-30641 +%patch213 -p1 -b .CVE-2021-26690 +%patch214 -p1 -b .CVE-2021-40438 +%patch215 -p1 -b .CVE-2021-26691 +%patch216 -p1 -b .CVE-2021-44790 # Patch in the vendor string sed -i '/^#define PLATFORM/s/Unix/%{vstring}/' os/unix/os.h @@ -397,6 +420,9 @@ if test "x${vmmn}" != "x%{mmn}"; then exit 1 fi +# A new logo which comes together with a new test page +cp %{SOURCE46} ./docs/icons/apache_pb3.png + # Provide default layout cp $RPM_SOURCE_DIR/config.layout . @@ -873,16 +899,34 @@ rm -rf $RPM_BUILD_ROOT %{_rpmconfigdir}/macros.d/macros.httpd %changelog -* Fri Oct 29 2021 Luboš Uhliarik - 2.4.37-39.2 -- Resolves: #2017856 - proxy rewrite to unix socket fails with CVE-2021-40438 - fix +* Mon Jan 10 2022 Luboš Uhliarik - 2.4.37-43.1 +- Resolves: #2035062 - CVE-2021-44790 httpd:2.4/httpd: mod_lua: possible buffer + overflow when parsing multipart content -* Thu Sep 30 2021 Luboš Uhliarik - 2.4.37-39.1 -- Resolves: #2007234 - CVE-2021-40438 httpd:2.4/httpd: mod_proxy: SSRF via +* Tue Oct 26 2021 Luboš Uhliarik - 2.4.37-43 +- Related: #2007235 - CVE-2021-40438 httpd:2.4/httpd: mod_proxy: SSRF via a crafted request uri-path -- Resolves: #2007646 - CVE-2021-26691 httpd:2.4/httpd: Heap overflow in + +* Thu Sep 30 2021 Luboš Uhliarik - 2.4.37-42 +- Resolves: #2007235 - CVE-2021-40438 httpd:2.4/httpd: mod_proxy: SSRF via + a crafted request uri-path +- Resolves: #2014063 - CVE-2021-26691 httpd:2.4/httpd: Heap overflow in mod_session +* Fri Jul 09 2021 Luboš Uhliarik - 2.4.37-41 +- Resolves: #1680111 - httpd sends reply to HTTPS GET using two TLS records +- Resolves: #1905613 - mod_ssl does not like valid certificate chain +- Resolves: #1935742 - [RFE] backport samesite/httponly/secure flags for + usertrack +- Resolves: #1972500 - CVE-2021-30641 httpd:2.4/httpd: MergeSlashes regression +- Resolves: #1968307 - CVE-2021-26690 httpd:2.4/httpd: mod_session NULL pointer + dereference in parser +- Resolves: #1934741 - Apache trademark update - new logo + +* Fri May 14 2021 Lubos Uhliarik - 2.4.37-40 +- Resolves: #1952557 - mod_proxy_wstunnel.html is a malformed XML +- Resolves: #1937334 - SSLProtocol with based virtual hosts + * Tue Jan 26 2021 Artem Egorenkov - 2.4.37-39 - prevent htcacheclean from while break when first file processed