From 947833e808610ecf1152bc5a6d928d13c7aeb2b3 Mon Sep 17 00:00:00 2001 From: webbuilder_pel7ppc64lebuilder0 Date: Sat, 27 Aug 2022 11:22:21 +0200 Subject: [PATCH] httpd update rel 95 Signed-off-by: webbuilder_pel7ppc64lebuilder0 --- SOURCES/README.confd | 1 + SOURCES/httpd-2.4.6-CVE-2017-15710.patch | 19 ++ SOURCES/httpd-2.4.6-CVE-2017-15715.patch | 190 ++++++++++++ SOURCES/httpd-2.4.6-CVE-2018-1283.patch | 23 ++ SOURCES/httpd-2.4.6-CVE-2018-1301.patch | 198 ++++++++++++ SOURCES/httpd-2.4.6-CVE-2018-1303.patch | 12 + SOURCES/httpd-2.4.6-CVE-2018-17199.patch | 46 +++ SOURCES/httpd-2.4.6-CVE-2019-10098.patch | 91 ++++++ SOURCES/httpd-2.4.6-CVE-2020-1934.patch | 71 +++++ SOURCES/httpd-2.4.6-r1583175.patch | 19 ++ SOURCES/httpd-2.4.6-r1826995.patch | 4 +- SOURCES/httpd-2.4.6-r1861793+.patch | 285 ++++++++++++++++++ SOURCES/httpd-2.4.6-r1862604.patch | 22 ++ .../httpd-2.4.6-session-expiry-updt-int.patch | 194 ++++++++++++ .../httpd-2.4.6-ssl-close-notify-client.patch | 161 ++++++++++ SPECS/httpd.spec | 43 ++- 16 files changed, 1376 insertions(+), 3 deletions(-) create mode 100644 SOURCES/httpd-2.4.6-CVE-2017-15710.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2017-15715.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2018-1283.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2018-1301.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2018-1303.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2018-17199.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2019-10098.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2020-1934.patch create mode 100644 SOURCES/httpd-2.4.6-r1583175.patch create mode 100644 SOURCES/httpd-2.4.6-r1861793+.patch create mode 100644 SOURCES/httpd-2.4.6-r1862604.patch create mode 100644 SOURCES/httpd-2.4.6-session-expiry-updt-int.patch create mode 100644 SOURCES/httpd-2.4.6-ssl-close-notify-client.patch diff --git a/SOURCES/README.confd b/SOURCES/README.confd index c91f04f..f5e9661 100644 --- a/SOURCES/README.confd +++ b/SOURCES/README.confd @@ -6,3 +6,4 @@ addition to the directory /etc/httpd/conf.modules.d/, which contains configuration files necessary to load modules. Files are processed in alphabetical order. + diff --git a/SOURCES/httpd-2.4.6-CVE-2017-15710.patch b/SOURCES/httpd-2.4.6-CVE-2017-15710.patch new file mode 100644 index 0000000..d8f02c9 --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2017-15710.patch @@ -0,0 +1,19 @@ +--- a/modules/aaa/mod_authnz_ldap.c 2018/02/15 17:33:04 1824335 ++++ b/modules/aaa/mod_authnz_ldap.c 2018/02/15 17:42:14 1824336 +@@ -126,9 +126,13 @@ + + charset = (char*) apr_hash_get(charset_conversions, language, APR_HASH_KEY_STRING); + +- if (!charset) { +- language[2] = '\0'; +- charset = (char*) apr_hash_get(charset_conversions, language, APR_HASH_KEY_STRING); ++ /* ++ * Test if language values like 'en-US' return a match from the charset ++ * conversion map when shortened to 'en'. ++ */ ++ if (!charset && strlen(language) > 3 && language[2] == '-') { ++ char *language_short = apr_pstrndup(p, language, 2); ++ charset = (char*) apr_hash_get(charset_conversions, language_short, APR_HASH_KEY_STRING); + } + + if (charset) { diff --git a/SOURCES/httpd-2.4.6-CVE-2017-15715.patch b/SOURCES/httpd-2.4.6-CVE-2017-15715.patch new file mode 100644 index 0000000..74e3770 --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2017-15715.patch @@ -0,0 +1,190 @@ +diff --git a/include/ap_regex.h b/include/ap_regex.h +index 5122154..349ae83 100644 +--- a/include/ap_regex.h ++++ b/include/ap_regex.h +@@ -77,6 +77,8 @@ extern "C" { + #define AP_REG_NOMEM 0x20 /* nomem in our code */ + #define AP_REG_DOTALL 0x40 /* perl's /s flag */ + ++#define AP_REG_DOLLAR_ENDONLY 0x200 /**< '$' matches at end of subject string only */ ++ + /* Error values: */ + enum { + AP_REG_ASSERT = 1, /** internal error ? */ +@@ -100,6 +102,26 @@ typedef struct { + + /* The functions */ + ++/** ++ * Get default compile flags ++ * @return Bitwise OR of AP_REG_* flags ++ */ ++AP_DECLARE(int) ap_regcomp_get_default_cflags(void); ++ ++/** ++ * Set default compile flags ++ * @param cflags Bitwise OR of AP_REG_* flags ++ */ ++AP_DECLARE(void) ap_regcomp_set_default_cflags(int cflags); ++ ++/** ++ * Get the AP_REG_* corresponding to the string. ++ * @param name The name (i.e. AP_REG_) ++ * @return The AP_REG_*, or zero if the string is unknown ++ * ++ */ ++AP_DECLARE(int) ap_regcomp_default_cflag_by_name(const char *name); ++ + /** + * Compile a regular expression. + * @param preg Returned compiled regex +diff --git a/server/core.c b/server/core.c +index b3240a0..e073ddf 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -48,6 +48,7 @@ + #include "mod_core.h" + #include "mod_proxy.h" + #include "ap_listen.h" ++#include "ap_regex.h" + + #include "mod_so.h" /* for ap_find_loaded_module_symbol */ + +@@ -2646,6 +2647,58 @@ static const char *virtualhost_section(cmd_parms *cmd, void *dummy, + return errmsg; + } + ++static const char *set_regex_default_options(cmd_parms *cmd, ++ void *dummy, ++ const char *arg) ++{ ++ const command_rec *thiscmd = cmd->cmd; ++ int cflags, cflag; ++ ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); ++ if (err != NULL) { ++ return err; ++ } ++ ++ cflags = ap_regcomp_get_default_cflags(); ++ while (*arg) { ++ const char *name = ap_getword_conf(cmd->pool, &arg); ++ int how = 0; ++ ++ if (strcasecmp(name, "none") == 0) { ++ cflags = 0; ++ continue; ++ } ++ ++ if (*name == '+') { ++ name++; ++ how = +1; ++ } ++ else if (*name == '-') { ++ name++; ++ how = -1; ++ } ++ ++ cflag = ap_regcomp_default_cflag_by_name(name); ++ if (!cflag) { ++ return apr_psprintf(cmd->pool, "%s: option '%s' unknown", ++ thiscmd->name, name); ++ } ++ ++ if (how > 0) { ++ cflags |= cflag; ++ } ++ else if (how < 0) { ++ cflags &= ~cflag; ++ } ++ else { ++ cflags = cflag; ++ } ++ } ++ ap_regcomp_set_default_cflags(cflags); ++ ++ return NULL; ++} ++ + static const char *set_server_alias(cmd_parms *cmd, void *dummy, + const char *arg) + { +@@ -4164,6 +4217,9 @@ AP_INIT_TAKE12("RLimitNPROC", no_set_limit, NULL, + OR_ALL, "soft/hard limits for max number of processes per uid"), + #endif + ++AP_INIT_RAW_ARGS("RegexDefaultOptions", set_regex_default_options, NULL, RSRC_CONF, ++ "default options for regexes (prefixed by '+' to add, '-' to del)"), ++ + /* internal recursion stopper */ + AP_INIT_TAKE12("LimitInternalRecursion", set_recursion_limit, NULL, RSRC_CONF, + "maximum recursion depth of internal redirects and subrequests"), +@@ -4569,6 +4625,8 @@ static int core_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptem + apr_pool_cleanup_register(pconf, NULL, reset_config_defines, + apr_pool_cleanup_null); + ++ ap_regcomp_set_default_cflags(AP_REG_DOLLAR_ENDONLY); ++ + mpm_common_pre_config(pconf); + + return OK; +diff --git a/server/util_pcre.c b/server/util_pcre.c +index 1e83cad..d7df400 100644 +--- a/server/util_pcre.c ++++ b/server/util_pcre.c +@@ -110,6 +110,38 @@ AP_DECLARE(void) ap_regfree(ap_regex_t *preg) + * Compile a regular expression * + *************************************************/ + ++static int default_cflags = AP_REG_DOLLAR_ENDONLY; ++ ++AP_DECLARE(int) ap_regcomp_get_default_cflags(void) ++{ ++ return default_cflags; ++} ++ ++AP_DECLARE(void) ap_regcomp_set_default_cflags(int cflags) ++{ ++ default_cflags = cflags; ++} ++ ++AP_DECLARE(int) ap_regcomp_default_cflag_by_name(const char *name) ++{ ++ int cflag = 0; ++ ++ if (strcasecmp(name, "ICASE") == 0) { ++ cflag = AP_REG_ICASE; ++ } ++ else if (strcasecmp(name, "DOTALL") == 0) { ++ cflag = AP_REG_DOTALL; ++ } ++ else if (strcasecmp(name, "DOLLAR_ENDONLY") == 0) { ++ cflag = AP_REG_DOLLAR_ENDONLY; ++ } ++ else if (strcasecmp(name, "EXTENDED") == 0) { ++ cflag = AP_REG_EXTENDED; ++ } ++ ++ return cflag; ++} ++ + /* + * Arguments: + * preg points to a structure for recording the compiled expression +@@ -126,12 +158,16 @@ AP_DECLARE(int) ap_regcomp(ap_regex_t * preg, const char *pattern, int cflags) + int errcode = 0; + int options = 0; + ++ cflags |= default_cflags; + if ((cflags & AP_REG_ICASE) != 0) + options |= PCRE_CASELESS; + if ((cflags & AP_REG_NEWLINE) != 0) + options |= PCRE_MULTILINE; + if ((cflags & AP_REG_DOTALL) != 0) + options |= PCRE_DOTALL; ++ if ((cflags & AP_REG_DOLLAR_ENDONLY) != 0) ++ options |= PCRE_DOLLAR_ENDONLY; ++ + + preg->re_pcre = + pcre_compile2(pattern, options, &errcode, &errorptr, &erroffset, NULL); diff --git a/SOURCES/httpd-2.4.6-CVE-2018-1283.patch b/SOURCES/httpd-2.4.6-CVE-2018-1283.patch new file mode 100644 index 0000000..c51bb4f --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2018-1283.patch @@ -0,0 +1,23 @@ +--- a/modules/session/mod_session.c 2018/02/16 13:39:47 1824476 ++++ b/modules/session/mod_session.c 2018/02/16 13:41:31 1824477 +@@ -510,12 +510,15 @@ + */ + ap_session_load(r, &z); + +- if (z && conf->env) { +- session_identity_encode(r, z); +- if (z->encoded) { +- apr_table_set(r->subprocess_env, HTTP_SESSION, z->encoded); +- z->encoded = NULL; ++ if (conf->env) { ++ if (z) { ++ session_identity_encode(r, z); ++ if (z->encoded) { ++ apr_table_set(r->subprocess_env, HTTP_SESSION, z->encoded); ++ z->encoded = NULL; ++ } + } ++ apr_table_unset(r->headers_in, "Session"); + } + + return OK; diff --git a/SOURCES/httpd-2.4.6-CVE-2018-1301.patch b/SOURCES/httpd-2.4.6-CVE-2018-1301.patch new file mode 100644 index 0000000..e03a444 --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2018-1301.patch @@ -0,0 +1,198 @@ +diff --git a/server/protocol.c b/server/protocol.c +index 9e23325..8428129 100644 +--- a/server/protocol.c ++++ b/server/protocol.c +@@ -222,6 +222,12 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, + int fold = flags & AP_GETLINE_FOLD; + int crlf = flags & AP_GETLINE_CRLF; + ++ if (!n) { ++ /* Needs room for NUL byte at least */ ++ *read = 0; ++ return APR_BADARG; ++ } ++ + /* + * Initialize last_char as otherwise a random value will be compared + * against APR_ASCII_LF at the end of the loop if bb only contains +@@ -235,14 +241,15 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, + rv = ap_get_brigade(r->proto_input_filters, bb, AP_MODE_GETLINE, + APR_BLOCK_READ, 0); + if (rv != APR_SUCCESS) { +- return rv; ++ goto cleanup; + } + + /* Something horribly wrong happened. Someone didn't block! + * (this also happens at the end of each keepalive connection) + */ + if (APR_BRIGADE_EMPTY(bb)) { +- return APR_EGENERAL; ++ rv = APR_EGENERAL; ++ goto cleanup; + } + + for (e = APR_BRIGADE_FIRST(bb); +@@ -260,7 +267,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, + + rv = apr_bucket_read(e, &str, &len, APR_BLOCK_READ); + if (rv != APR_SUCCESS) { +- return rv; ++ goto cleanup; + } + + if (len == 0) { +@@ -273,17 +280,8 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, + + /* Would this overrun our buffer? If so, we'll die. */ + if (n < bytes_handled + len) { +- *read = bytes_handled; +- if (*s) { +- /* ensure this string is NUL terminated */ +- if (bytes_handled > 0) { +- (*s)[bytes_handled-1] = '\0'; +- } +- else { +- (*s)[0] = '\0'; +- } +- } +- return APR_ENOSPC; ++ rv = APR_ENOSPC; ++ goto cleanup; + } + + /* Do we have to handle the allocation ourselves? */ +@@ -291,7 +289,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, + /* We'll assume the common case where one bucket is enough. */ + if (!*s) { + current_alloc = len; +- *s = apr_palloc(r->pool, current_alloc); ++ *s = apr_palloc(r->pool, current_alloc + 1); + } + else if (bytes_handled + len > current_alloc) { + /* Increase the buffer size */ +@@ -302,7 +300,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, + new_size = (bytes_handled + len) * 2; + } + +- new_buffer = apr_palloc(r->pool, new_size); ++ new_buffer = apr_palloc(r->pool, new_size + 1); + + /* Copy what we already had. */ + memcpy(new_buffer, *s, bytes_handled); +@@ -326,19 +324,15 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, + } + } + +- if (crlf && (last_char <= *s || last_char[-1] != APR_ASCII_CR)) { +- *last_char = '\0'; +- bytes_handled = last_char - *s; +- *read = bytes_handled; +- return APR_EINVAL; +- } +- +- /* Now NUL-terminate the string at the end of the line; ++ /* Now terminate the string at the end of the line; + * if the last-but-one character is a CR, terminate there */ + if (last_char > *s && last_char[-1] == APR_ASCII_CR) { + last_char--; + } +- *last_char = '\0'; ++ else if (crlf) { ++ rv = APR_EINVAL; ++ goto cleanup; ++ } + bytes_handled = last_char - *s; + + /* If we're folding, we have more work to do. +@@ -358,7 +352,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, + rv = ap_get_brigade(r->proto_input_filters, bb, AP_MODE_SPECULATIVE, + APR_BLOCK_READ, 1); + if (rv != APR_SUCCESS) { +- return rv; ++ goto cleanup; + } + + if (APR_BRIGADE_EMPTY(bb)) { +@@ -375,7 +369,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, + rv = apr_bucket_read(e, &str, &len, APR_BLOCK_READ); + if (rv != APR_SUCCESS) { + apr_brigade_cleanup(bb); +- return rv; ++ goto cleanup; + } + + /* Found one, so call ourselves again to get the next line. +@@ -392,10 +386,8 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, + if (c == APR_ASCII_BLANK || c == APR_ASCII_TAB) { + /* Do we have enough space? We may be full now. */ + if (bytes_handled >= n) { +- *read = n; +- /* ensure this string is terminated */ +- (*s)[n-1] = '\0'; +- return APR_ENOSPC; ++ rv = APR_ENOSPC; ++ goto cleanup; + } + else { + apr_size_t next_size, next_len; +@@ -408,7 +400,6 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, + tmp = NULL; + } + else { +- /* We're null terminated. */ + tmp = last_char; + } + +@@ -417,7 +408,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, + rv = ap_rgetline_core(&tmp, next_size, + &next_len, r, 0, bb); + if (rv != APR_SUCCESS) { +- return rv; ++ goto cleanup; + } + + if (do_alloc && next_len > 0) { +@@ -431,7 +422,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, + memcpy(new_buffer, *s, bytes_handled); + + /* copy the new line, including the trailing null */ +- memcpy(new_buffer + bytes_handled, tmp, next_len + 1); ++ memcpy(new_buffer + bytes_handled, tmp, next_len); + *s = new_buffer; + } + +@@ -444,8 +435,21 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, + } + } + } ++ ++cleanup: ++ if (bytes_handled >= n) { ++ bytes_handled = n - 1; ++ } ++ if (*s) { ++ /* ensure the string is NUL terminated */ ++ (*s)[bytes_handled] = '\0'; ++ } + *read = bytes_handled; + ++ if (rv != APR_SUCCESS) { ++ return rv; ++ } ++ + /* PR#43039: We shouldn't accept NULL bytes within the line */ + if (strlen(*s) < bytes_handled) { + return APR_EINVAL; +@@ -484,6 +488,11 @@ AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int flags) + apr_size_t len; + apr_bucket_brigade *tmp_bb; + ++ if (n < 1) { ++ /* Can't work since we always NUL terminate */ ++ return -1; ++ } ++ + tmp_bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); + rv = ap_rgetline(&tmp_s, n, &len, r, flags, tmp_bb); + apr_brigade_destroy(tmp_bb); diff --git a/SOURCES/httpd-2.4.6-CVE-2018-1303.patch b/SOURCES/httpd-2.4.6-CVE-2018-1303.patch new file mode 100644 index 0000000..f0b6bde --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2018-1303.patch @@ -0,0 +1,12 @@ +--- a/modules/cache/mod_cache_socache.c 2018/02/16 13:32:48 1824474 ++++ b/modules/cache/mod_cache_socache.c 2018/02/16 13:34:35 1824475 +@@ -213,7 +213,8 @@ + "Premature end of cache headers."); + return APR_EGENERAL; + } +- while (apr_isspace(buffer[colon])) { ++ /* Do not go past the \r from above as apr_isspace('\r') is true */ ++ while (apr_isspace(buffer[colon]) && (colon < *slider)) { + colon++; + } + apr_table_addn(table, apr_pstrndup(r->pool, (const char *) buffer diff --git a/SOURCES/httpd-2.4.6-CVE-2018-17199.patch b/SOURCES/httpd-2.4.6-CVE-2018-17199.patch new file mode 100644 index 0000000..70bfea2 --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2018-17199.patch @@ -0,0 +1,46 @@ +diff --git a/modules/session/mod_session.c b/modules/session/mod_session.c +index 7213eb3..3e73c7a 100644 +--- a/modules/session/mod_session.c ++++ b/modules/session/mod_session.c +@@ -126,15 +126,9 @@ static apr_status_t ap_session_load(request_rec * r, session_rec ** z) + + /* found a session that hasn't expired? */ + now = apr_time_now(); +- if (!zz || (zz->expiry && zz->expiry < now)) { +- +- /* no luck, create a blank session */ +- zz = (session_rec *) apr_pcalloc(r->pool, sizeof(session_rec)); +- zz->pool = r->pool; +- zz->entries = apr_table_make(zz->pool, 10); +- +- } +- else { ++ ++ if (zz){ ++ /* load the session attibutes */ + rv = ap_run_session_decode(r, zz); + if (OK != rv) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01817) +@@ -142,8 +136,22 @@ static apr_status_t ap_session_load(request_rec * r, session_rec ** z) + "session not loaded: %s", r->uri); + return rv; + } ++ ++ /* invalidate session if session is expired */ ++ if (zz && zz->expiry && zz->expiry < now){ ++ zz = NULL; ++ } + } + ++ if (!zz || (zz->expiry && zz->expiry < now)) { ++ ++ /* no luck, create a blank session */ ++ zz = (session_rec *) apr_pcalloc(r->pool, sizeof(session_rec)); ++ zz->pool = r->pool; ++ zz->entries = apr_table_make(zz->pool, 10); ++ ++ } ++ + /* make sure the expiry is set, if present */ + if (!zz->expiry && dconf->maxage) { + zz->expiry = now + dconf->maxage * APR_USEC_PER_SEC; diff --git a/SOURCES/httpd-2.4.6-CVE-2019-10098.patch b/SOURCES/httpd-2.4.6-CVE-2019-10098.patch new file mode 100644 index 0000000..f8298cc --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2019-10098.patch @@ -0,0 +1,91 @@ +diff --git a/include/ap_regex.h b/include/ap_regex.h +index 349ae83..952e77a 100644 +--- a/include/ap_regex.h ++++ b/include/ap_regex.h +@@ -79,6 +79,12 @@ extern "C" { + + #define AP_REG_DOLLAR_ENDONLY 0x200 /**< '$' matches at end of subject string only */ + ++#define AP_REG_NO_DEFAULT 0x400 /**< Don't implicitely add AP_REG_DEFAULT options */ ++ ++#define AP_REG_MATCH "MATCH_" /**< suggested prefix for ap_regname */ ++ ++#define AP_REG_DEFAULT (AP_REG_DOTALL|AP_REG_DOLLAR_ENDONLY) ++ + /* Error values: */ + enum { + AP_REG_ASSERT = 1, /** internal error ? */ +diff --git a/modules/filters/mod_substitute.c b/modules/filters/mod_substitute.c +index 15cd8ee..69af111 100644 +--- a/modules/filters/mod_substitute.c ++++ b/modules/filters/mod_substitute.c +@@ -599,8 +599,10 @@ static const char *set_pattern(cmd_parms *cmd, void *cfg, const char *line) + + /* first see if we can compile the regex */ + if (!is_pattern) { +- r = ap_pregcomp(cmd->pool, from, AP_REG_EXTENDED | +- (ignore_case ? AP_REG_ICASE : 0)); ++ int flags = AP_REG_NO_DEFAULT ++ | (ap_regcomp_get_default_cflags() & AP_REG_DOLLAR_ENDONLY) ++ | (ignore_case ? AP_REG_ICASE : 0); ++ r = ap_pregcomp(cmd->pool, from, flags); + if (!r) + return "Substitute could not compile regex"; + } +diff --git a/server/core.c b/server/core.c +index d4af287..6ae0f5f 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -4625,7 +4625,7 @@ static int core_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptem + apr_pool_cleanup_register(pconf, NULL, reset_config_defines, + apr_pool_cleanup_null); + +- ap_regcomp_set_default_cflags(AP_REG_DOLLAR_ENDONLY); ++ ap_regcomp_set_default_cflags(AP_REG_DEFAULT); + + mpm_common_pre_config(pconf); + +diff --git a/server/util_pcre.c b/server/util_pcre.c +index d7df400..f778c75 100644 +--- a/server/util_pcre.c ++++ b/server/util_pcre.c +@@ -110,7 +110,7 @@ AP_DECLARE(void) ap_regfree(ap_regex_t *preg) + * Compile a regular expression * + *************************************************/ + +-static int default_cflags = AP_REG_DOLLAR_ENDONLY; ++static int default_cflags = AP_REG_DEFAULT; + + AP_DECLARE(int) ap_regcomp_get_default_cflags(void) + { +@@ -158,7 +158,8 @@ AP_DECLARE(int) ap_regcomp(ap_regex_t * preg, const char *pattern, int cflags) + int errcode = 0; + int options = 0; + +- cflags |= default_cflags; ++ if ((cflags & AP_REG_NO_DEFAULT) == 0) ++ cflags |= default_cflags; + if ((cflags & AP_REG_ICASE) != 0) + options |= PCRE_CASELESS; + if ((cflags & AP_REG_NEWLINE) != 0) +diff --git a/server/util_regex.c b/server/util_regex.c +index 73eccec..5038b99 100644 +--- a/server/util_regex.c ++++ b/server/util_regex.c +@@ -93,6 +93,7 @@ AP_DECLARE(ap_rxplus_t*) ap_rxplus_compile(apr_pool_t *pool, + } + + /* anything after the current delimiter is flags */ ++ ret->flags = ap_regcomp_get_default_cflags() & AP_REG_DOLLAR_ENDONLY; + while (*++endp) { + switch (*endp) { + case 'i': ret->flags |= AP_REG_ICASE; break; +@@ -105,7 +106,7 @@ AP_DECLARE(ap_rxplus_t*) ap_rxplus_compile(apr_pool_t *pool, + default: break; /* we should probably be stricter here */ + } + } +- if (ap_regcomp(&ret->rx, rxstr, ret->flags) == 0) { ++ if (ap_regcomp(&ret->rx, rxstr, AP_REG_NO_DEFAULT | ret->flags) == 0) { + apr_pool_cleanup_register(pool, &ret->rx, rxplus_cleanup, + apr_pool_cleanup_null); + } diff --git a/SOURCES/httpd-2.4.6-CVE-2020-1934.patch b/SOURCES/httpd-2.4.6-CVE-2020-1934.patch new file mode 100644 index 0000000..ac82c7e --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2020-1934.patch @@ -0,0 +1,71 @@ +diff --git a/modules/proxy/mod_proxy_ftp.c b/modules/proxy/mod_proxy_ftp.c +index 680be8b..10382df 100644 +--- a/modules/proxy/mod_proxy_ftp.c ++++ b/modules/proxy/mod_proxy_ftp.c +@@ -218,7 +218,7 @@ static int ftp_check_string(const char *x) + * (EBCDIC) machines either. + */ + static apr_status_t ftp_string_read(conn_rec *c, apr_bucket_brigade *bb, +- char *buff, apr_size_t bufflen, int *eos) ++ char *buff, apr_size_t bufflen, int *eos, apr_size_t *outlen) + { + apr_bucket *e; + apr_status_t rv; +@@ -230,6 +230,7 @@ static apr_status_t ftp_string_read(conn_rec *c, apr_bucket_brigade *bb, + /* start with an empty string */ + buff[0] = 0; + *eos = 0; ++ *outlen = 0; + + /* loop through each brigade */ + while (!found) { +@@ -273,6 +274,7 @@ static apr_status_t ftp_string_read(conn_rec *c, apr_bucket_brigade *bb, + if (len > 0) { + memcpy(pos, response, len); + pos += len; ++ *outlen += len; + } + } + APR_BUCKET_REMOVE(e); +@@ -386,28 +388,37 @@ static int ftp_getrc_msg(conn_rec *ftp_ctrl, apr_bucket_brigade *bb, char *msgbu + char buff[5]; + char *mb = msgbuf, *me = &msgbuf[msglen]; + apr_status_t rv; ++ apr_size_t nread; ++ + int eos; + +- if (APR_SUCCESS != (rv = ftp_string_read(ftp_ctrl, bb, response, sizeof(response), &eos))) { ++ if (APR_SUCCESS != (rv = ftp_string_read(ftp_ctrl, bb, response, sizeof(response), &eos, &nread))) { + return -1; + } + /* + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, + "<%s", response); + */ ++ if (nread < 4) { ++ ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, APLOGNO(10229) "Malformed FTP response '%s'", response); ++ *mb = '\0'; ++ return -1; ++ } ++ ++ + if (!apr_isdigit(response[0]) || !apr_isdigit(response[1]) || +- !apr_isdigit(response[2]) || (response[3] != ' ' && response[3] != '-')) ++ !apr_isdigit(response[2]) || (response[3] != ' ' && response[3] != '-')) + status = 0; + else + status = 100 * response[0] + 10 * response[1] + response[2] - 111 * '0'; + + mb = apr_cpystrn(mb, response + 4, me - mb); + +- if (response[3] == '-') { ++ if (response[3] == '-') { /* multi-line reply "123-foo\nbar\n123 baz" */ + memcpy(buff, response, 3); + buff[3] = ' '; + do { +- if (APR_SUCCESS != (rv = ftp_string_read(ftp_ctrl, bb, response, sizeof(response), &eos))) { ++ if (APR_SUCCESS != (rv = ftp_string_read(ftp_ctrl, bb, response, sizeof(response), &eos, &nread))) { + return -1; + } + mb = apr_cpystrn(mb, response + (' ' == response[0] ? 1 : 4), me - mb); diff --git a/SOURCES/httpd-2.4.6-r1583175.patch b/SOURCES/httpd-2.4.6-r1583175.patch new file mode 100644 index 0000000..4270a4c --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1583175.patch @@ -0,0 +1,19 @@ +--- a/modules/mappers/mod_alias.c 2014/03/30 18:15:25 1583174 ++++ b/modules/mappers/mod_alias.c 2014/03/30 18:20:09 1583175 +@@ -371,15 +371,11 @@ + } + } + else { +- int pathlen = strlen(found) - +- (strlen(r->uri + regm[0].rm_eo)); +- AP_DEBUG_ASSERT(pathlen >= 0); +- AP_DEBUG_ASSERT(pathlen <= strlen(found)); + ap_set_context_info(r, + apr_pstrmemdup(r->pool, r->uri, + regm[0].rm_eo), + apr_pstrmemdup(r->pool, found, +- pathlen)); ++ strlen(found))); + } + } + else { diff --git a/SOURCES/httpd-2.4.6-r1826995.patch b/SOURCES/httpd-2.4.6-r1826995.patch index abbcb33..c179178 100644 --- a/SOURCES/httpd-2.4.6-r1826995.patch +++ b/SOURCES/httpd-2.4.6-r1826995.patch @@ -132,8 +132,8 @@ index 5ff35f5..9dc236c 100644 * Perform OCSP-based revocation checks */ - if (ok && sc->server->ocsp_enabled) { -+ if (ok && ((sc->server->ocsp_mask & SSL_OCSPCHECK_CHAIN) || -+ (errdepth == 0 && (sc->server->ocsp_mask & SSL_OCSPCHECK_LEAF)))) { ++ if (ok && ((mctx->ocsp_mask & SSL_OCSPCHECK_CHAIN) || ++ (errdepth == 0 && (mctx->ocsp_mask & SSL_OCSPCHECK_LEAF)))) { /* If there was an optional verification error, it's not * possible to perform OCSP validation since the issuer may be * missing/untrusted. Fail in that case. */ diff --git a/SOURCES/httpd-2.4.6-r1861793+.patch b/SOURCES/httpd-2.4.6-r1861793+.patch new file mode 100644 index 0000000..dd7bd81 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1861793+.patch @@ -0,0 +1,285 @@ +# ./pullrev.sh 1861793 1862611 1862612 +http://svn.apache.org/viewvc?view=revision&revision=1861793 +http://svn.apache.org/viewvc?view=revision&revision=1862611 +http://svn.apache.org/viewvc?view=revision&revision=1862612 +http://svn.apache.org/viewvc?view=revision&revision=1862724 + +--- httpd-2.4.6/configure.in.r1861793+ ++++ httpd-2.4.6/configure.in +@@ -464,6 +464,28 @@ + AC_SEARCH_LIBS(crypt, crypt) + CRYPT_LIBS="$LIBS" + APACHE_SUBST(CRYPT_LIBS) ++ ++if test "$ac_cv_search_crypt" != "no"; then ++ # Test crypt() with the SHA-512 test vector from https://akkadia.org/drepper/SHA-crypt.txt ++ AC_CACHE_CHECK([whether crypt() supports SHA-2], [ap_cv_crypt_sha2], [ ++ AC_RUN_IFELSE([AC_LANG_PROGRAM([[ ++#include ++#include ++#include ++ ++#define PASSWD_0 "Hello world!" ++#define SALT_0 "\$6\$saltstring" ++#define EXPECT_0 "\$6\$saltstring\$svn8UoSVapNtMuq1ukKS4tPQd8iKwSMHWjl/O817G3uBnIFNjnQJu" \ ++ "esI68u4OTLiBFdcbYEdFCoEOfaS35inz1" ++]], [char *result = crypt(PASSWD_0, SALT_0); ++ if (!result) return 1; ++ if (strcmp(result, EXPECT_0)) return 2; ++])], [ap_cv_crypt_sha2=yes], [ap_cv_crypt_sha2=no])]) ++ if test "$ap_cv_crypt_sha2" = yes; then ++ AC_DEFINE([HAVE_CRYPT_SHA2], 1, [Define if crypt() supports SHA-2 hashes]) ++ fi ++fi ++ + LIBS="$saved_LIBS" + + dnl See Comment #Spoon +--- httpd-2.4.6/docs/man/htpasswd.1.r1861793+ ++++ httpd-2.4.6/docs/man/htpasswd.1 +@@ -27,16 +27,16 @@ + .SH "SYNOPSIS" + + .PP +-\fBhtpasswd\fR [ -\fBc\fR ] [ -\fBi\fR ] [ -\fBm\fR | -\fBB\fR | -\fBd\fR | -\fBs\fR | -\fBp\fR ] [ -\fBC\fR \fIcost\fR ] [ -\fBD\fR ] [ -\fBv\fR ] \fIpasswdfile\fR \fIusername\fR ++\fBhtpasswd\fR [ -\fBc\fR ] [ -\fBi\fR ] [ -\fBm\fR | -\fBB\fR | -\fBd\fR | -\fBs\fR | -\fBp\fR ] [ -\fBr\fR \fIrounds\fR ] [ -\fBC\fR \fIcost\fR ] [ -\fBD\fR ] [ -\fBv\fR ] \fIpasswdfile\fR \fIusername\fR + + .PP +-\fBhtpasswd\fR -\fBb\fR [ -\fBc\fR ] [ -\fBm\fR | -\fBB\fR | -\fBd\fR | -\fBs\fR | -\fBp\fR ] [ -\fBC\fR \fIcost\fR ] [ -\fBD\fR ] [ -\fBv\fR ] \fIpasswdfile\fR \fIusername\fR \fIpassword\fR ++\fBhtpasswd\fR -\fBb\fR [ -\fBc\fR ] [ -\fBm\fR | -\fBB\fR | -\fBd\fR | -\fBs\fR | -\fBp\fR ] [ -\fBr\fR \fIrounds\fR ] [ -\fBC\fR \fIcost\fR ] [ -\fBD\fR ] [ -\fBv\fR ] \fIpasswdfile\fR \fIusername\fR \fIpassword\fR + + .PP +-\fBhtpasswd\fR -\fBn\fR [ -\fBi\fR ] [ -\fBm\fR | -\fBB\fR | -\fBd\fR | -\fBs\fR | -\fBp\fR ] [ -\fBC\fR \fIcost\fR ] \fIusername\fR ++\fBhtpasswd\fR -\fBn\fR [ -\fBi\fR ] [ -\fBm\fR | -\fBB\fR | -\fBd\fR | -\fBs\fR | -\fBp\fR ] [ -\fBr\fR \fIrounds\fR ] [ -\fBC\fR \fIcost\fR ] \fIusername\fR + + .PP +-\fBhtpasswd\fR -\fBnb\fR [ -\fBm\fR | -\fBB\fR | -\fBd\fR | -\fBs\fR | -\fBp\fR ] [ -\fBC\fR \fIcost\fR ] \fIusername\fR \fIpassword\fR ++\fBhtpasswd\fR -\fBnb\fR [ -\fBm\fR | -\fBB\fR | -\fBd\fR | -\fBs\fR | -\fBp\fR ] [ -\fBr\fR \fIrounds\fR ] [ -\fBC\fR \fIcost\fR ] \fIusername\fR \fIpassword\fR + + + .SH "SUMMARY" +@@ -48,7 +48,7 @@ + Resources available from the Apache HTTP server can be restricted to just the users listed in the files created by htpasswd\&. This program can only manage usernames and passwords stored in a flat-file\&. It can encrypt and display password information for use in other types of data stores, though\&. To use a DBM database see dbmmanage or htdbm\&. + + .PP +-htpasswd encrypts passwords using either bcrypt, a version of MD5 modified for Apache, SHA1, or the system's crypt() routine\&. Files managed by htpasswd may contain a mixture of different encoding types of passwords; some user records may have bcrypt or MD5-encrypted passwords while others in the same file may have passwords encrypted with crypt()\&. +++\fBhtpasswd\fR encrypts passwords using either bcrypt, a version of MD5 modified for Apache, SHA-1, or the system's \fBcrypt()\fR routine\&. SHA-2-based hashes (SHA-256 and SHA-512) are supported for \fBcrypt()\fR\&. Files managed by \fBhtpasswd\fR may contain a mixture of different encoding types of passwords; some user records may have bcrypt or MD5-encrypted passwords while others in the same file may have passwords encrypted with \fBcrypt()\fR\&. + + .PP + This manual page only lists the command line arguments\&. For details of the directives necessary to configure user authentication in httpd see the Apache manual, which is part of the Apache distribution or can be found at http://httpd\&.apache\&.org/\&. +@@ -73,17 +73,26 @@ + -m + Use MD5 encryption for passwords\&. This is the default (since version 2\&.2\&.18)\&. + .TP ++-2 ++Use SHA-256 \fBcrypt()\fR based hashes for passwords\&. This is supported on most Unix platforms\&. ++.TP ++-5 ++Use SHA-512 \fBcrypt()\fR based hashes for passwords\&. This is supported on most Unix platforms\&. ++.TP + -B + Use bcrypt encryption for passwords\&. This is currently considered to be very secure\&. + .TP + -C + This flag is only allowed in combination with -B (bcrypt encryption)\&. It sets the computing time used for the bcrypt algorithm (higher is more secure but slower, default: 5, valid: 4 to 31)\&. + .TP ++-r ++This flag is only allowed in combination with \fB-2\fR or \fB-5\fR\&. It sets the number of hash rounds used for the SHA-2 algorithms (higher is more secure but slower; the default is 5,000)\&. ++.TP + -d + Use crypt() encryption for passwords\&. This is not supported by the httpd server on Windows and Netware\&. This algorithm limits the password length to 8 characters\&. This algorithm is \fBinsecure\fR by today's standards\&. It used to be the default algorithm until version 2\&.2\&.17\&. + .TP + -s +-Use SHA encryption for passwords\&. Facilitates migration from/to Netscape servers using the LDAP Directory Interchange Format (ldif)\&. This algorithm is \fBinsecure\fR by today's standards\&. ++Use SHA-1 encryption for passwords\&. Facilitates migration from/to Netscape servers using the LDAP Directory Interchange Format (ldif)\&. This algorithm is \fBinsecure\fR by today's standards\&. + .TP + -p + Use plaintext passwords\&. Though htpasswd will support creation on all platforms, the httpd daemon will only accept plain text passwords on Windows and Netware\&. +@@ -152,11 +161,14 @@ + When using the crypt() algorithm, note that only the first 8 characters of the password are used to form the password\&. If the supplied password is longer, the extra characters will be silently discarded\&. + + .PP +-The SHA encryption format does not use salting: for a given password, there is only one encrypted representation\&. The crypt() and MD5 formats permute the representation by prepending a random salt string, to make dictionary attacks against the passwords more difficult\&. ++The SHA-1 encryption format does not use salting: for a given password, there is only one encrypted representation\&. The crypt() and MD5 formats permute the representation by prepending a random salt string, to make dictionary attacks against the passwords more difficult\&. + + .PP +-The SHA and crypt() formats are insecure by today's standards\&. +- ++The SHA-1 and crypt() formats are insecure by today's standards\&. ++ ++.PP ++The SHA-2-based \fBcrypt()\fR formats (SHA-256 and SHA-512) are supported on most modern Unix systems, and follow the specification at https://www\&.akkadia\&.org/drepper/SHA-crypt\&.txt\& ++ + .SH "RESTRICTIONS" + + .PP +--- httpd-2.4.6/support/htpasswd.c.r1861793+ ++++ httpd-2.4.6/support/htpasswd.c +@@ -93,28 +93,32 @@ + static void usage(void) + { + apr_file_printf(errfile, "Usage:" NL +- "\thtpasswd [-cimBdpsDv] [-C cost] passwordfile username" NL +- "\thtpasswd -b[cmBdpsDv] [-C cost] passwordfile username password" NL ++ "\thtpasswd [-cimB25dpsDv] [-C cost] [-r rounds] passwordfile username" NL ++ "\thtpasswd -b[cmB25dpsDv] [-C cost] [-r rounds] passwordfile username password" NL + NL +- "\thtpasswd -n[imBdps] [-C cost] username" NL +- "\thtpasswd -nb[mBdps] [-C cost] username password" NL ++ "\thtpasswd -n[imB25dps] [-C cost] [-r rounds] username" NL ++ "\thtpasswd -nb[mB25dps] [-C cost] [-r rounds] username password" NL + " -c Create a new file." NL + " -n Don't update file; display results on stdout." NL + " -b Use the password from the command line rather than prompting " + "for it." NL + " -i Read password from stdin without verification (for script usage)." NL + " -m Force MD5 encryption of the password (default)." NL +- " -B Force bcrypt encryption of the password (very secure)." NL ++ " -2 Force SHA-256 crypt() hash of the password (secure)." NL ++ " -5 Force SHA-512 crypt() hash of the password (secure)." NL ++ " -B Force bcrypt aencryption of the password (very secure)." NL + " -C Set the computing time used for the bcrypt algorithm" NL + " (higher is more secure but slower, default: %d, valid: 4 to 31)." NL ++ " -r Set the number of rounds used for the SHA-256, SHA-512 algorithms" NL ++ " (higher is more secure but slower, default: 5000)." NL + " -d Force CRYPT encryption of the password (8 chars max, insecure)." NL +- " -s Force SHA encryption of the password (insecure)." NL ++ " -s Force SHA-1 encryption of the password (insecure)." NL + " -p Do not encrypt the password (plaintext, insecure)." NL + " -D Delete the specified user." NL + " -v Verify password for the specified user." NL + "On other systems than Windows and NetWare the '-p' flag will " + "probably not work." NL +- "The SHA algorithm does not use a salt and is less secure than the " ++ "The SHA-1 algorithm does not use a salt and is less secure than the " + "MD5 algorithm." NL, + BCRYPT_DEFAULT_COST + ); +@@ -173,7 +177,7 @@ + if (rv != APR_SUCCESS) + exit(ERR_SYNTAX); + +- while ((rv = apr_getopt(state, "cnmspdBbDiC:v", &opt, &opt_arg)) == APR_SUCCESS) { ++ while ((rv = apr_getopt(state, "cnmspdBbDi25C:r:v", &opt, &opt_arg)) == APR_SUCCESS) { + switch (opt) { + case 'c': + *mask |= APHTP_NEWFILE; +--- httpd-2.4.6/support/passwd_common.c.r1861793+ ++++ httpd-2.4.6/support/passwd_common.c +@@ -185,10 +185,15 @@ + #if CRYPT_ALGO_SUPPORTED + char *cbuf; + #endif ++#ifdef HAVE_CRYPT_SHA2 ++ const char *setting; ++ char method; ++#endif + +- if (ctx->cost != 0 && ctx->alg != ALG_BCRYPT) { ++ if (ctx->cost != 0 && ctx->alg != ALG_BCRYPT ++ && ctx->alg != ALG_CRYPT_SHA256 && ctx->alg != ALG_CRYPT_SHA512 ) { + apr_file_printf(errfile, +- "Warning: Ignoring -C argument for this algorithm." NL); ++ "Warning: Ignoring -C/-r argument for this algorithm." NL); + } + + if (ctx->passwd == NULL) { +@@ -246,6 +251,34 @@ + break; + #endif /* CRYPT_ALGO_SUPPORTED */ + ++#ifdef HAVE_CRYPT_SHA2 ++ case ALG_CRYPT_SHA256: ++ case ALG_CRYPT_SHA512: ++ ret = generate_salt(salt, 16, &ctx->errstr, ctx->pool); ++ if (ret != 0) ++ break; ++ ++ method = ctx->alg == ALG_CRYPT_SHA256 ? '5': '6'; ++ ++ if (ctx->cost) ++ setting = apr_psprintf(ctx->pool, "$%c$rounds=%d$%s", ++ method, ctx->cost, salt); ++ else ++ setting = apr_psprintf(ctx->pool, "$%c$%s", ++ method, salt); ++ ++ cbuf = crypt(pw, setting); ++ if (cbuf == NULL) { ++ rv = APR_FROM_OS_ERROR(errno); ++ ctx->errstr = apr_psprintf(ctx->pool, "crypt() failed: %pm", &rv); ++ ret = ERR_PWMISMATCH; ++ break; ++ } ++ ++ apr_cpystrn(ctx->out, cbuf, ctx->out_len - 1); ++ break; ++#endif /* HAVE_CRYPT_SHA2 */ ++ + #if BCRYPT_ALGO_SUPPORTED + case ALG_BCRYPT: + rv = apr_generate_random_bytes((unsigned char*)salt, 16); +@@ -294,6 +327,19 @@ + case 's': + ctx->alg = ALG_APSHA; + break; ++#ifdef HAVE_CRYPT_SHA2 ++ case '2': ++ ctx->alg = ALG_CRYPT_SHA256; ++ break; ++ case '5': ++ ctx->alg = ALG_CRYPT_SHA512; ++ break; ++#else ++ case '2': ++ case '5': ++ ctx->errstr = "SHA-2 crypt() algorithms are not supported on this platform."; ++ return ERR_ALG_NOT_SUPP; ++#endif + case 'p': + ctx->alg = ALG_PLAIN; + #if !PLAIN_ALGO_SUPPORTED +@@ -324,11 +370,12 @@ + return ERR_ALG_NOT_SUPP; + #endif + break; +- case 'C': { ++ case 'C': ++ case 'r': { + char *endptr; + long num = strtol(opt_arg, &endptr, 10); + if (*endptr != '\0' || num <= 0) { +- ctx->errstr = "argument to -C must be a positive integer"; ++ ctx->errstr = "argument to -C/-r must be a positive integer"; + return ERR_SYNTAX; + } + ctx->cost = num; +--- httpd-2.4.6/support/passwd_common.h.r1861793+ ++++ httpd-2.4.6/support/passwd_common.h +@@ -28,6 +28,8 @@ + #include "apu_version.h" + #endif + ++#include "ap_config_auto.h" ++ + #define MAX_STRING_LEN 256 + + #define ALG_PLAIN 0 +@@ -35,6 +37,8 @@ + #define ALG_APMD5 2 + #define ALG_APSHA 3 + #define ALG_BCRYPT 4 ++#define ALG_CRYPT_SHA256 5 ++#define ALG_CRYPT_SHA512 6 + + #define BCRYPT_DEFAULT_COST 5 + +@@ -79,7 +83,7 @@ + apr_size_t out_len; + char *passwd; + int alg; +- int cost; ++ int cost; /* cost for bcrypt, rounds for SHA-2 */ + enum { + PW_PROMPT = 0, + PW_ARG, diff --git a/SOURCES/httpd-2.4.6-r1862604.patch b/SOURCES/httpd-2.4.6-r1862604.patch new file mode 100644 index 0000000..83c6c4a --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1862604.patch @@ -0,0 +1,22 @@ +--- a/docs/conf/magic 2019/07/05 11:22:46 1862603 ++++ b/docs/conf/magic 2019/07/05 11:26:12 1862604 +@@ -87,7 +87,7 @@ + # Microsoft WAVE format (*.wav) + # [GRR 950115: probably all of the shorts and longs should be leshort/lelong] + # Microsoft RIFF +-0 string RIFF audio/unknown ++0 string RIFF + # - WAVE format + >8 string WAVE audio/x-wav + # MPEG audio. +--- a/modules/metadata/mod_mime_magic.c 2019/07/05 11:22:46 1862603 ++++ b/modules/metadata/mod_mime_magic.c 2019/07/05 11:26:12 1862604 +@@ -606,7 +606,7 @@ + /* high overhead for 1 char - just hope they don't do this much */ + str[0] = c; + str[1] = '\0'; +- return magic_rsl_add(r, str); ++ return magic_rsl_add(r, apr_pstrdup(r->pool, str)); + } + + /* allocate and copy a contiguous string from a result string list */ diff --git a/SOURCES/httpd-2.4.6-session-expiry-updt-int.patch b/SOURCES/httpd-2.4.6-session-expiry-updt-int.patch new file mode 100644 index 0000000..56d6c53 --- /dev/null +++ b/SOURCES/httpd-2.4.6-session-expiry-updt-int.patch @@ -0,0 +1,194 @@ +diff --git a/docs/manual/mod/mod_session.html.en b/docs/manual/mod/mod_session.html.en +index 96a61e6..4ecc97d 100644 +--- a/docs/manual/mod/mod_session.html.en ++++ b/docs/manual/mod/mod_session.html.en +@@ -69,6 +69,7 @@ +
  • SessionHeader
  • +
  • SessionInclude
  • +
  • SessionMaxAge
  • ++
  • SessionExpiryUpdateInterval
  • + +

    Topics

    +
      +@@ -494,6 +495,37 @@ AuthName realm + +

      Setting the maxage to zero disables session expiry.

      + ++ ++
      top
      ++

      SessionExpiryUpdateInterval Directive

      ++ ++ ++ ++ ++ ++ ++
      Description:Define the number of seconds a session's expiry may change without the session being updated
      Syntax:SessionExpiryUpdateInterval interval
      Default:SessionExpiryUpdateInterval 0 (always update)
      Context:server config, virtual host, directory, .htaccess
      Module:mod_session
      ++

      The SessionExpiryUpdateInterval directive allows ++ sessions to avoid the cost associated with writing the session each request ++ when only the expiry time has changed. This can be used to make a website ++ more efficient or reduce load on a database when using ++ mod_session_dbd. The session is always written if the data ++ stored in the session has changed or the expiry has changed by more than the ++ configured interval.

      ++ ++

      Setting the interval to zero disables this directive, and the session ++ expiry is refreshed for each request.

      ++ ++

      This directive only has an effect when combined with SessionMaxAge to enable session ++ expiry. Sessions without an expiry are only written when the data stored in ++ the session has changed.

      ++ ++

      Warning

      ++

      Because the session expiry may not be refreshed with each request, it's ++ possible for sessions to expire up to interval seconds early. ++ Using a small interval usually provides sufficient savings while having a ++ minimal effect on expiry resolution.

      ++ +
      + +
      +diff --git a/modules/session/mod_session.c b/modules/session/mod_session.c +index 3e73c7a..83bf3fc 100644 +--- a/modules/session/mod_session.c ++++ b/modules/session/mod_session.c +@@ -177,6 +177,7 @@ static apr_status_t ap_session_save(request_rec * r, session_rec * z) + { + if (z) { + apr_time_t now = apr_time_now(); ++ apr_time_t initialExpiry = z->expiry; + int rv = 0; + + session_dir_conf *dconf = ap_get_module_config(r->per_dir_config, +@@ -202,6 +203,17 @@ static apr_status_t ap_session_save(request_rec * r, session_rec * z) + z->maxage = dconf->maxage; + } + ++ /* don't save if the only change is the expiry by a small amount */ ++ if (!z->dirty && dconf->expiry_update_time ++ && (z->expiry - initialExpiry < dconf->expiry_update_time)) { ++ return APR_SUCCESS; ++ } ++ ++ /* also don't save sessions that didn't change at all */ ++ if (!z->dirty && !z->maxage) { ++ return APR_SUCCESS; ++ } ++ + /* encode the session */ + rv = ap_run_session_encode(r, z); + if (OK != rv) { +@@ -544,6 +556,10 @@ static void *merge_session_dir_config(apr_pool_t * p, void *basev, void *addv) + new->env_set = add->env_set || base->env_set; + new->includes = apr_array_append(p, base->includes, add->includes); + new->excludes = apr_array_append(p, base->excludes, add->excludes); ++ new->expiry_update_time = (add->expiry_update_set == 0) ++ ? base->expiry_update_time ++ : add->expiry_update_time; ++ new->expiry_update_set = add->expiry_update_set || base->expiry_update_set; + + return new; + } +@@ -613,6 +629,21 @@ static const char *add_session_exclude(cmd_parms * cmd, void *dconf, const char + return NULL; + } + ++static const char * ++ set_session_expiry_update(cmd_parms * parms, void *dconf, const char *arg) ++{ ++ session_dir_conf *conf = dconf; ++ ++ conf->expiry_update_time = atoi(arg); ++ if (conf->expiry_update_time < 0) { ++ return "SessionExpiryUpdateInterval must be positive or nul"; ++ } ++ conf->expiry_update_time = apr_time_from_sec(conf->expiry_update_time); ++ conf->expiry_update_set = 1; ++ ++ return NULL; ++} ++ + + static const command_rec session_cmds[] = + { +@@ -628,6 +659,9 @@ static const command_rec session_cmds[] = + "URL prefixes to include in the session. Defaults to all URLs"), + AP_INIT_TAKE1("SessionExclude", add_session_exclude, NULL, RSRC_CONF|OR_AUTHCFG, + "URL prefixes to exclude from the session. Defaults to no URLs"), ++ AP_INIT_TAKE1("SessionExpiryUpdateInterval", set_session_expiry_update, NULL, RSRC_CONF|OR_AUTHCFG, ++ "time interval for which a session's expiry time may change " ++ "without having to be rewritten. Zero to disable"), + {NULL} + }; + +diff --git a/modules/session/mod_session.h b/modules/session/mod_session.h +index a6dd5e9..bdeb532 100644 +--- a/modules/session/mod_session.h ++++ b/modules/session/mod_session.h +@@ -115,6 +115,9 @@ typedef struct { + * URLs included if empty */ + apr_array_header_t *excludes; /* URL prefixes to be excluded. No + * URLs excluded if empty */ ++ apr_time_t expiry_update_time; /* seconds the session expiry may change and ++ * not have to be rewritten */ ++ int expiry_update_set; + } session_dir_conf; + + /** +diff --git a/modules/session/mod_session_cookie.c b/modules/session/mod_session_cookie.c +index 6a02322..4aa75e4 100644 +--- a/modules/session/mod_session_cookie.c ++++ b/modules/session/mod_session_cookie.c +@@ -60,9 +60,6 @@ static apr_status_t session_cookie_save(request_rec * r, session_rec * z) + session_cookie_dir_conf *conf = ap_get_module_config(r->per_dir_config, + &session_cookie_module); + +- /* don't cache auth protected pages */ +- apr_table_addn(r->headers_out, "Cache-Control", "no-cache"); +- + /* create RFC2109 compliant cookie */ + if (conf->name_set) { + if (z->encoded && z->encoded[0]) { +@@ -162,6 +159,9 @@ static apr_status_t session_cookie_load(request_rec * r, session_rec ** z) + /* put the session in the notes so we don't have to parse it again */ + apr_table_setn(m->notes, note, (char *)zz); + ++ /* don't cache auth protected pages */ ++ apr_table_addn(r->headers_out, "Cache-Control", "no-cache, private"); ++ + return OK; + + } +diff --git a/modules/session/mod_session_dbd.c b/modules/session/mod_session_dbd.c +index cf65e5a..20ef72e 100644 +--- a/modules/session/mod_session_dbd.c ++++ b/modules/session/mod_session_dbd.c +@@ -243,6 +243,9 @@ static apr_status_t session_dbd_load(request_rec * r, session_rec ** z) + /* put the session in the notes so we don't have to parse it again */ + apr_table_setn(m->notes, note, (char *)zz); + ++ /* don't cache pages with a session */ ++ apr_table_addn(r->headers_out, "Cache-Control", "no-cache, private"); ++ + return OK; + + } +@@ -407,9 +410,6 @@ static apr_status_t session_dbd_save(request_rec * r, session_rec * z) + if (conf->name_set || conf->name2_set) { + char *oldkey = NULL, *newkey = NULL; + +- /* don't cache pages with a session */ +- apr_table_addn(r->headers_out, "Cache-Control", "no-cache"); +- + /* if the session is new or changed, make a new session ID */ + if (z->uuid) { + oldkey = apr_pcalloc(r->pool, APR_UUID_FORMATTED_LENGTH + 1); +@@ -456,7 +456,7 @@ static apr_status_t session_dbd_save(request_rec * r, session_rec * z) + else if (conf->peruser) { + + /* don't cache pages with a session */ +- apr_table_addn(r->headers_out, "Cache-Control", "no-cache"); ++ apr_table_addn(r->headers_out, "Cache-Control", "no-cache, private"); + + if (r->user) { + ret = dbd_save(r, r->user, r->user, z->encoded, z->expiry); diff --git a/SOURCES/httpd-2.4.6-ssl-close-notify-client.patch b/SOURCES/httpd-2.4.6-ssl-close-notify-client.patch new file mode 100644 index 0000000..04afef3 --- /dev/null +++ b/SOURCES/httpd-2.4.6-ssl-close-notify-client.patch @@ -0,0 +1,161 @@ +diff --git a/include/http_connection.h b/include/http_connection.h +index 2192507..924ddda 100644 +--- a/include/http_connection.h ++++ b/include/http_connection.h +@@ -47,9 +47,18 @@ extern "C" { + */ + AP_CORE_DECLARE(void) ap_process_connection(conn_rec *c, void *csd); + ++/** ++ * Shutdown the connection for writing. ++ * @param c The connection to shutdown ++ * @param flush Whether or not to flush pending data before ++ * @return APR_SUCCESS or the underlying error ++ */ ++AP_CORE_DECLARE(apr_status_t) ap_shutdown_conn(conn_rec *c, int flush); ++ + /** + * Flushes all remain data in the client send buffer + * @param c The connection to flush ++ * @remark calls ap_shutdown_conn(c, 1) + */ + AP_CORE_DECLARE(void) ap_flush_conn(conn_rec *c); + +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index 8be833a..6c79a1a 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -2886,6 +2886,33 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, + } + } + ++static apr_status_t connection_shutdown(void *theconn) ++{ ++ proxy_conn_rec *conn = (proxy_conn_rec *)theconn; ++ conn_rec *c = conn->connection; ++ if (c) { ++ if (!c->aborted) { ++ apr_interval_time_t saved_timeout = 0; ++ apr_socket_timeout_get(conn->sock, &saved_timeout); ++ if (saved_timeout) { ++ apr_socket_timeout_set(conn->sock, 0); ++ } ++ ++ (void)ap_shutdown_conn(c, 0); ++ c->aborted = 1; ++ ++ if (saved_timeout) { ++ apr_socket_timeout_set(conn->sock, saved_timeout); ++ } ++ } ++ ++ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(02642) ++ "proxy: connection shutdown"); ++ } ++ return APR_SUCCESS; ++} ++ ++ + PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function, + proxy_conn_rec *conn, + conn_rec *c, +@@ -2958,6 +2985,11 @@ PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function, + } + apr_socket_timeout_set(conn->sock, current_timeout); + ++ /* Shutdown the connection before closing it (eg. SSL connections ++ * need to be close-notify-ed). ++ */ ++ apr_pool_pre_cleanup_register(conn->scpool, conn, connection_shutdown); ++ + return OK; + } + +diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c +index fbd701f..a8778d4 100644 +--- a/modules/ssl/ssl_util_ssl.c ++++ b/modules/ssl/ssl_util_ssl.c +@@ -166,6 +166,7 @@ int SSL_smart_shutdown(SSL *ssl) + { + int i; + int rc; ++ int flush; + + /* + * Repeat the calls, because SSL_shutdown internally dispatches through a +@@ -175,8 +176,20 @@ int SSL_smart_shutdown(SSL *ssl) + * connection and OpenSSL cannot recognize it. + */ + rc = 0; ++ flush = !(SSL_get_shutdown(ssl) & SSL_SENT_SHUTDOWN); + for (i = 0; i < 4 /* max 2x pending + 2x data = 4 */; i++) { +- if ((rc = SSL_shutdown(ssl))) ++ rc = SSL_shutdown(ssl); ++ if (rc >= 0 && flush && (SSL_get_shutdown(ssl) & SSL_SENT_SHUTDOWN)) { ++ /* Once the close notity is sent through the output filters, ++ * ensure it is flushed through the socket. ++ */ ++ if (BIO_flush(SSL_get_wbio(ssl)) <= 0) { ++ rc = -1; ++ break; ++ } ++ flush = 0; ++ } ++ if (rc != 0) + break; + } + return rc; +diff --git a/server/connection.c b/server/connection.c +index 6e4495f..4942c77 100644 +--- a/server/connection.c ++++ b/server/connection.c +@@ -64,22 +64,32 @@ AP_IMPLEMENT_HOOK_RUN_ALL(int,pre_connection,(conn_rec *c, void *csd),(c, csd),O + #define MAX_SECS_TO_LINGER 30 + #endif + +-AP_CORE_DECLARE(void) ap_flush_conn(conn_rec *c) ++AP_CORE_DECLARE(apr_status_t) ap_shutdown_conn(conn_rec *c, int flush) + { ++ apr_status_t rv; + apr_bucket_brigade *bb; + apr_bucket *b; + + bb = apr_brigade_create(c->pool, c->bucket_alloc); + +- /* FLUSH bucket */ +- b = apr_bucket_flush_create(c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(bb, b); ++ if (flush) { ++ /* FLUSH bucket */ ++ b = apr_bucket_flush_create(c->bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(bb, b); ++ } + + /* End Of Connection bucket */ + b = ap_bucket_eoc_create(c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(bb, b); + +- ap_pass_brigade(c->output_filters, bb); ++ rv = ap_pass_brigade(c->output_filters, bb); ++ apr_brigade_destroy(bb); ++ return rv; ++} ++ ++AP_CORE_DECLARE(void) ap_flush_conn(conn_rec *c) ++{ ++ (void)ap_shutdown_conn(c, 1); + } + + /* we now proceed to read from the client until we get EOF, or until +diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c +index 5852685..defa109 100644 +--- a/server/mpm/event/event.c ++++ b/server/mpm/event/event.c +@@ -841,6 +841,7 @@ static int start_lingering_close_nonblocking(event_conn_state_t *cs) + apr_socket_t *csd = cs->pfd.desc.s; + + if (c->aborted ++ || ap_shutdown_conn(c, 0) != APR_SUCCESS || c->aborted + || apr_socket_shutdown(csd, APR_SHUTDOWN_WRITE) != APR_SUCCESS) { + apr_socket_close(csd); + apr_pool_clear(cs->p); diff --git a/SPECS/httpd.spec b/SPECS/httpd.spec index b68a3b9..67d34e2 100644 --- a/SPECS/httpd.spec +++ b/SPECS/httpd.spec @@ -15,7 +15,7 @@ Summary: Apache HTTP Server Name: httpd Version: 2.4.6 -Release: 90%{?dist} +Release: 95%{?dist} URL: http://httpd.apache.org/ Source0: http://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2 ### TODO: we need to create a powerel version @@ -72,6 +72,9 @@ Patch36: httpd-2.4.6-r1573626.patch Patch37: httpd-2.4.6-uds.patch Patch38: httpd-2.4.6-upn.patch Patch39: httpd-2.4.6-r1664565.patch +Patch40: httpd-2.4.6-r1861793+.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1715981 +Patch41: httpd-2.4.6-session-expiry-updt-int.patch # Bug fixes Patch51: httpd-2.4.3-sslsninotreq.patch Patch55: httpd-2.4.4-malformed-host.patch @@ -192,6 +195,12 @@ Patch138: httpd-2.4.6-r1515372.patch Patch139: httpd-2.4.6-r1824872.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1583218 Patch140: httpd-2.4.6-r1833014.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1673457 +Patch141: httpd-2.4.6-r1583175.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1649470 +Patch142: httpd-2.4.6-r1862604.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1724879 +Patch143: httpd-2.4.6-ssl-close-notify-client.patch # Security fixes Patch200: httpd-2.4.6-CVE-2013-6438.patch @@ -218,6 +227,14 @@ Patch220: httpd-2.4.6-CVE-2017-9798.patch Patch221: httpd-2.4.6-CVE-2018-1312.patch Patch222: httpd-2.4.6-CVE-2019-0217.patch Patch223: httpd-2.4.6-CVE-2019-0220.patch +Patch224: httpd-2.4.6-CVE-2017-15710.patch +Patch225: httpd-2.4.6-CVE-2018-1301.patch +Patch226: httpd-2.4.6-CVE-2018-17199.patch +Patch227: httpd-2.4.6-CVE-2017-15715.patch +Patch228: httpd-2.4.6-CVE-2019-10098.patch +Patch229: httpd-2.4.6-CVE-2018-1303.patch +Patch230: httpd-2.4.6-CVE-2018-1283.patch +Patch240: httpd-2.4.6-CVE-2020-1934.patch License: ASL 2.0 Group: System Environment/Daemons @@ -352,6 +369,8 @@ rm modules/ssl/ssl_engine_dh.c %patch37 -p1 -b .uds %patch38 -p1 -b .upn %patch39 -p1 -b .r1664565 +%patch40 -p1 -b .r1861793+ +%patch41 -p1 -b .session-expiry %patch51 -p1 -b .sninotreq %patch55 -p1 -b .malformedhost @@ -431,6 +450,17 @@ rm modules/ssl/ssl_engine_dh.c %patch130 -p1 -b .r1811976 %patch131 -p1 -b .r1650310 %patch132 -p1 -b .r1530999 +%patch133 -p1 -b .r1555539 +%patch134 -p1 -b .r1523536 +%patch135 -p1 -b .r1826995 +%patch136 -p1 -b .defaultport-proxy +%patch137 -p1 -b .r1825120 +%patch138 -p1 -b .r1515372 +%patch139 -p1 -b .r1824872 +%patch140 -p1 -b .r1833014 +%patch141 -p1 -b .r1583175 +%patch142 -p1 -b .r1862604 +%patch143 -p1 -b .ssl-close-notify-client %patch200 -p1 -b .cve6438 %patch201 -p1 -b .cve0098 @@ -453,6 +483,17 @@ rm modules/ssl/ssl_engine_dh.c %patch218 -p1 -b .cve7679 %patch219 -p1 -b .cve9788 %patch220 -p1 -b .cve9798 +%patch221 -p1 -b .cve1312 +%patch222 -p1 -b .cve0217 +%patch223 -p1 -b .cve0220 +%patch224 -p1 -b .cve15710 +%patch225 -p1 -b .cve1301 +%patch226 -p1 -b .cve17199 +%patch227 -p1 -b .cve15715 +%patch228 -p1 -b .cve10098 +%patch229 -p1 -b .cve1303 +%patch230 -p1 -b .cve1283 +%patch240 -p1 -b .cve1934 # Patch in the vendor string and the release string sed -i '/^#define PLATFORM/s/Unix/%{vstring}/' os/unix/os.h