diff --git a/httpd-2.4.37-CVE-2023-25690.patch b/httpd-2.4.37-CVE-2023-25690.patch
index 878d6e62fa6572b578bec57987348cfaf185730d..5b24a06b70f423fcab83ddfd4af9a97ada7aa683 100644
--- a/httpd-2.4.37-CVE-2023-25690.patch
+++ b/httpd-2.4.37-CVE-2023-25690.patch
@@ -1,5 +1,28 @@
+diff --git a/docs/manual/mod/mod_rewrite.html.en b/docs/manual/mod/mod_rewrite.html.en
+index 815ec72..2b8ed35 100644
+--- a/docs/manual/mod/mod_rewrite.html.en
++++ b/docs/manual/mod/mod_rewrite.html.en
+@@ -1265,7 +1265,17 @@ cannot use $N in the substitution string!
+
mod_rewrite has to unescape URLs before mapping them,
so backreferences are unescaped at the time they are applied.
-@@ -120,6 +116,16 @@ when the backend may break if presented with an unescaped URL.
An alternative to this flag is using a RewriteCond to capture against %{THE_REQUEST} which will capture
strings in the encoded form.
RewriteRule
+and the space must not be the last character in the list.
+
-+# Escape spaces and question marks. ++# Escape spaces and question marks. The quotes around the final argument ++# are required when a space is included. +RewriteRule "^search/(.*)$" "/search.php?term=$1" "[B= ?]"++ ++To limit the characters escaped this way, see #flag_bne ++and #flag_bctls
+++BNP|backrefnoplus (don't escape space to +)
+@@ -127,8 +137,40 @@ strings in the encoded form. + in a backreference to %20 rather than '+'. Useful when the backreference + will be used in the path component rather than the query string. + ++++# Escape spaces to %20 in the path instead of + as used in form submission via ++# the query string ++RewriteRule "^search/(.*)$" "/search.php/$1" "[B,BNP]" ++++ +This flag is available in version 2.4.26 and later.
+ ++++++BCTLS
++The [BCTLS] flag is similar to the [B] flag, but only escapes ++control characters and the space character. This is the same set of ++characters rejected when they are copied into the query string unencoded. ++
++ ++++# Escape control characters and spaces ++RewriteRule "^search/(.*)$" "/search.php/$1" "[BCTLS]" ++++ +++++BNE
++The list of characters in [BNE=...] are treated as exclusions to the ++characters of the [B] or [BCTLS] flags. The listed characters will not be ++escaped. ++
++ ++++# Escape the default characters, but leave / ++RewriteRule "^search/(.*)$" "/search.php?term=$1" "[B,BNE=/]" ++++ +++C|chain
+@@ -204,7 +246,7 @@ browsers that support this feature. +Consider this example:
+ +RewriteEngine On +-RewriteRule "^/index\.html" "-" [CO=frontdoor:yes:.example.com:1440:/]++RewriteRule "^/index\.html" "-" [CO=frontdoor:yes:.example.com:1440:/] + + +In the example give, the rule doesn't rewrite the request. +@@ -410,8 +452,8 @@ argument to
+ +index.php, however, theindex.php, theRewriteRulewill be skipped.RewriteBase "/" +-RewriteCond "%{REQUEST_URI}" "!=/index.php" +-RewriteRule "^(.*)" "/index.php?req=$1" [L,PT]++RewriteCond "%{REQUEST_URI}" !=/index.php ++RewriteRule "^(.*)" "/index.php?req=$1" [L,PT] + ++@@ -434,11 +476,11 @@ pattern still matches (i.e., while the URI still contains an +A), perform this substitution (i.e., replace the +Awith aB). + +-In 2.4.8 and later, this module returns an error after 32,000 iterations to ++
In 2.4.8 and later, this module returns an error after 10,000 iterations to + protect against unintended looping. An alternative maximum number of + iterations can be specified by adding to the N flag.
+# Be willing to replace 1 character in each pass of the loop +-RewriteRule "(.+)[><;]$" "$1" [N=64000] ++RewriteRule "(.+)[><;]$" "$1" [N=32000] + # ... or, give up if after 10 loops + RewriteRule "(.+)[><;]$" "$1" [N=10]+ +@@ -681,19 +723,21 @@ URI in request' warnings. +The [S] flag is used to skip rules that you don't want to run. The + syntax of the skip flag is [S=N], where N signifies + the number of rules to skip (provided the
++RewriteRule and any preceding+-RewriteRulematches). This can be thought of as agoto+-statement in your rewrite ruleset. In the following example, we only want +-to run theRewriteRuleif the +-requested URI doesn't correspond with an actual file.++RewriteConddirectives match). This can be thought of as a ++gotostatement in your rewrite ruleset. In the following ++example, we only want to run the++RewriteRuleif the requested URI doesn't correspond with an ++actual file. + +# Is the request for a non-existent file? +-RewriteCond "%{REQUEST_FILENAME}" "!-f" +-RewriteCond "%{REQUEST_FILENAME}" "!-d" ++RewriteCond "%{REQUEST_FILENAME}" !-f ++RewriteCond "%{REQUEST_FILENAME}" !-d + # If so, skip these two RewriteRules +-RewriteRule ".?" "-" [S=2] ++RewriteRule ".?" "-" [S=2] + +-RewriteRule "(.*\.gif)" "images.php?$1" +-RewriteRule "(.*\.html)" "docs.php?$1"++RewriteRule "(.*\.gif)" "images.php?$1" ++RewriteRule "(.*\.html)" "docs.php?$1" + + +This technique is useful because a
+RewriteCondonly applies to the +@@ -705,18 +749,18 @@ use this to make pseudo if-then-else constructs: The last rule of + the then-clause becomesskip=N, where N is the + number of rules in the else-clause:# Does the file exist? +-RewriteCond "%{REQUEST_FILENAME}" "!-f" +-RewriteCond "%{REQUEST_FILENAME}" "!-d" ++RewriteCond "%{REQUEST_FILENAME}" !-f ++RewriteCond "%{REQUEST_FILENAME}" !-d + # Create an if-then-else construct by skipping 3 lines if we meant to go to the "else" stanza. +-RewriteRule ".?" "-" [S=3] ++RewriteRule ".?" "-" [S=3] + + # IF the file exists, then: +- RewriteRule "(.*\.gif)" "images.php?$1" ++ RewriteRule "(.*\.gif)" "images.php?$1" + RewriteRule "(.*\.html)" "docs.php?$1" + # Skip past the "else" stanza. +- RewriteRule ".?" "-" [S=1] ++ RewriteRule ".?" "-" [S=1] + # ELSE... +- RewriteRule "(.*)" "404.php?file=$1" ++ RewriteRule "(.*)" "404.php?file=$1" + # END+ + +@@ -733,7 +777,7 @@ sent. This has the same effect as the# Serve .pl files as plain text +-RewriteRule "\.pl$" "-" [T=text/plain] ++RewriteRule "\.pl$" "-" [T=text/plain] + + +Or, perhaps, if you have a camera that produces jpeg images without +@@ -741,7 +785,7 @@ file extensions, you could force those images to be served with the + correct MIME type by virtue of their file names:
+ +# Files with 'IMG' in the name are jpg images. +-RewriteRule "IMG" "-" [T=image/jpg]++RewriteRule "IMG" "-" [T=image/jpg] + + +Please note that this is a trivial example, and could be better done diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c -index 38dbb24..c3937ad 100644 +index 38dbb24..b71c67c 100644 --- a/modules/mappers/mod_rewrite.c +++ b/modules/mappers/mod_rewrite.c -@@ -168,6 +168,7 @@ static const char* really_last_key = "rewrite_really_last"; +@@ -101,6 +101,8 @@ + #include "mod_rewrite.h" + #include "ap_expr.h" + ++#include "test_char.h" ++ + static ap_dbd_t *(*dbd_acquire)(request_rec*) = NULL; + static void (*dbd_prepare)(server_rec*, const char*, const char*) = NULL; + static const char* really_last_key = "rewrite_really_last"; +@@ -168,6 +170,8 @@ static const char* really_last_key = "rewrite_really_last"; #define RULEFLAG_END (1<<17) #define RULEFLAG_ESCAPENOPLUS (1<<18) #define RULEFLAG_QSLAST (1<<19) +#define RULEFLAG_QSNONE (1<<20) /* programattic only */ ++#define RULEFLAG_ESCAPECTLS (1<<21) /* return code of the rewrite rule * the result may be escaped - or not -@@ -761,15 +762,24 @@ static char *escape_absolute_uri(apr_pool_t *p, char *uri, unsigned scheme) +@@ -321,7 +325,8 @@ typedef struct { + data_item *cookie; /* added cookies */ + int skip; /* number of next rules to skip */ + int maxrounds; /* limit on number of loops with N flag */ +- char *escapes; /* specific backref escapes */ ++ const char *escapes; /* specific backref escapes */ ++ const char *noescapes; /* specific backref chars not to escape */ + } rewriterule_entry; + + typedef struct { +@@ -422,7 +427,9 @@ static const char *rewritemap_mutex_type = "rewrite-map"; + /* Optional functions imported from mod_ssl when loaded: */ + static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *rewrite_ssl_lookup = NULL; + static APR_OPTIONAL_FN_TYPE(ssl_is_https) *rewrite_is_https = NULL; +-static char *escape_backref(apr_pool_t *p, const char *path, const char *escapeme, int noplus); ++static char *escape_backref(apr_pool_t *p, const char *path, ++ const char *escapeme, const char *noescapeme, ++ int flags); + + /* + * +-------------------------------------------------------+ +@@ -645,18 +652,26 @@ static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix, + return where; + } + ++ + /* + * Escapes a backreference in a similar way as php's urlencode does. + * Based on ap_os_escape_path in server/util.c + */ +-static char *escape_backref(apr_pool_t *p, const char *path, const char *escapeme, int noplus) { +- char *copy = apr_palloc(p, 3 * strlen(path) + 3); ++static char *escape_backref(apr_pool_t *p, const char *path, ++ const char *escapeme, const char *noescapeme, ++ int flags) ++{ ++ char *copy = apr_palloc(p, 3 * strlen(path) + 1); + const unsigned char *s = (const unsigned char *)path; + unsigned char *d = (unsigned char *)copy; +- unsigned c; ++ int noplus = (flags & RULEFLAG_ESCAPENOPLUS) != 0; ++ int ctls = (flags & RULEFLAG_ESCAPECTLS) != 0; ++ unsigned char c; + + while ((c = *s)) { +- if (!escapeme) { ++ if (((ctls ? !TEST_CHAR(c, T_VCHAR_OBSTEXT) : !escapeme) ++ || (escapeme && ap_strchr_c(escapeme, c))) ++ && (!noescapeme || !ap_strchr_c(noescapeme, c))) { + if (apr_isalnum(c) || c == '_') { + *d++ = c; + } +@@ -667,23 +682,8 @@ static char *escape_backref(apr_pool_t *p, const char *path, const char *escapem + d = c2x(c, '%', d); + } + } +- else { +- const char *esc = escapeme; +- while (*esc) { +- if (c == *esc) { +- if (c == ' ' && !noplus) { +- *d++ = '+'; +- } +- else { +- d = c2x(c, '%', d); +- } +- break; +- } +- ++esc; +- } +- if (!*esc) { +- *d++ = c; +- } ++ else { ++ *d++ = c; + } + ++s; + } +@@ -761,15 +761,24 @@ static char *escape_absolute_uri(apr_pool_t *p, char *uri, unsigned scheme) ap_escape_uri(p, cp), NULL); } @@ -69,7 +333,7 @@ index 38dbb24..c3937ad 100644 /* don't touch, unless it's a scheme for which a query string makes sense. * See RFC 1738 and RFC 2368. -@@ -794,7 +804,7 @@ static void splitout_queryargs(request_rec *r, int qsappend, int qsdiscard, +@@ -794,7 +803,7 @@ static void splitout_queryargs(request_rec *r, int qsappend, int qsdiscard, olduri = apr_pstrdup(r->pool, r->filename); *q++ = '\0'; if (qsappend) { @@ -78,7 +342,7 @@ index 38dbb24..c3937ad 100644 r->args = apr_pstrcat(r->pool, q, "&" , r->args, NULL); } } -@@ -802,9 +812,9 @@ static void splitout_queryargs(request_rec *r, int qsappend, int qsdiscard, +@@ -802,9 +811,9 @@ static void splitout_queryargs(request_rec *r, int qsappend, int qsdiscard, r->args = apr_pstrdup(r->pool, q); } @@ -90,6 +354,16 @@ index 38dbb24..c3937ad 100644 if (!len) { r->args = NULL; } +@@ -2436,7 +2445,8 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry) + /* escape the backreference */ + char *tmp2, *tmp; + tmp = apr_pstrmemdup(pool, bri->source + bri->regmatch[n].rm_so, span); +- tmp2 = escape_backref(pool, tmp, entry->escapes, entry->flags & RULEFLAG_ESCAPENOPLUS); ++ tmp2 = escape_backref(pool, tmp, entry->escapes, entry->noescapes, ++ entry->flags); + rewritelog((ctx->r, 5, ctx->perdir, "escaping backreference '%s' to '%s'", + tmp, tmp2)); + @@ -2733,7 +2743,7 @@ static apr_status_t rewritelock_remove(void *data) * XXX: what an inclined parser. Seems we have to leave it so * for backwards compat. *sigh* @@ -128,7 +402,33 @@ index 38dbb24..c3937ad 100644 return apr_pstrcat(cmd->pool, "RewriteCond: bad argument line '", str, "'", NULL); } -@@ -3749,7 +3761,7 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf, +@@ -3500,13 +3512,24 @@ static const char *cmd_rewriterule_setflag(apr_pool_t *p, void *_cfg, + case 'B': + if (!*key || !strcasecmp(key, "ackrefescaping")) { + cfg->flags |= RULEFLAG_ESCAPEBACKREF; +- if (val && *val) { ++ if (val && *val) { + cfg->escapes = val; + } + } ++ else if (!strcasecmp(key, "NE")) { ++ if (val && *val) { ++ cfg->noescapes = val; ++ } ++ else { ++ return "flag 'BNE' wants a list of characters (i.e. [BNE=...])"; ++ } ++ } + else if (!strcasecmp(key, "NP") || !strcasecmp(key, "ackrefernoplus")) { + cfg->flags |= RULEFLAG_ESCAPENOPLUS; + } ++ else if (!strcasecmp(key, "CTLS")) { ++ cfg->flags |= RULEFLAG_ESCAPECTLS|RULEFLAG_ESCAPEBACKREF; ++ } + else { + ++error; + } +@@ -3749,7 +3772,7 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf, rewrite_server_conf *sconf; rewriterule_entry *newrule; ap_regex_t *regexp; @@ -137,7 +437,7 @@ index 38dbb24..c3937ad 100644 const char *err; sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module); -@@ -3763,7 +3775,7 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf, +@@ -3763,12 +3786,11 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf, } /* parse the argument line ourself */ @@ -146,13 +446,29 @@ index 38dbb24..c3937ad 100644 return apr_pstrcat(cmd->pool, "RewriteRule: bad argument line '", str, "'", NULL); } -@@ -3810,6 +3822,16 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf, + +- /* arg3: optional flags field */ + newrule->forced_mimetype = NULL; + newrule->forced_handler = NULL; + newrule->forced_responsecode = HTTP_MOVED_TEMPORARILY; +@@ -3777,6 +3799,9 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf, + newrule->cookie = NULL; + newrule->skip = 0; + newrule->maxrounds = REWRITE_MAX_ROUNDS; ++ newrule->escapes = newrule->noescapes = NULL; ++ ++ /* arg3: optional flags field */ + if (a3 != NULL) { + if ((err = cmd_parseflagfield(cmd->pool, newrule, a3, + cmd_rewriterule_setflag)) != NULL) { +@@ -3810,6 +3835,17 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf, newrule->flags |= RULEFLAG_NOSUB; } + if (*(a2_end-1) == '?') { + /* a literal ? at the end of the unsubstituted rewrite rule */ + newrule->flags |= RULEFLAG_QSNONE; ++ *(a2_end-1) = '\0'; /* trailing ? has done its job */ + } + else if (newrule->flags & RULEFLAG_QSDISCARD) { + if (NULL == ap_strchr(newrule->output, '?')) { @@ -163,7 +479,7 @@ index 38dbb24..c3937ad 100644 /* now, if the server or per-dir config holds an * array of RewriteCond entries, we take it for us * and clear the array -@@ -4215,9 +4237,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx) +@@ -4215,9 +4251,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx) r->path_info = NULL; } @@ -174,29 +490,78 @@ index 38dbb24..c3937ad 100644 /* Add the previously stripped per-directory location prefix, unless * (1) it's an absolute URL path and -@@ -4699,6 +4719,17 @@ static int hook_uri2file(request_rec *r) - unsigned skip; - apr_size_t flen; +@@ -4696,8 +4730,25 @@ static int hook_uri2file(request_rec *r) + } -+ if (r->args && *(ap_scan_vchar_obstext(r->args))) { + if (rulestatus) { +- unsigned skip; +- apr_size_t flen; ++ unsigned skip_absolute = is_absolute_uri(r->filename, NULL); ++ apr_size_t flen = r->filename ? strlen(r->filename) : 0; ++ int to_proxyreq = (flen > 6 && strncmp(r->filename, "proxy:", 6) == 0); ++ int will_escape = skip_absolute && (rulestatus != ACTION_NOESCAPE); ++ ++ if (r->args ++ && !will_escape ++ && *(ap_scan_vchar_obstext(r->args))) { + /* + * We have a raw control character or a ' ' in r->args. + * Correct encoding was missed. ++ * Correct encoding was missed and we're not going to escape ++ * it before returning. + */ + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10410) + "Rewritten query string contains control " + "characters or spaces"); + return HTTP_FORBIDDEN; + } -+ + if (ACTION_STATUS == rulestatus) { int n = r->status; +@@ -4706,8 +4757,7 @@ static int hook_uri2file(request_rec *r) + return n; + } -@@ -4983,6 +5014,17 @@ static int hook_fixup(request_rec *r) - if (rulestatus) { - unsigned skip; +- flen = r->filename ? strlen(r->filename) : 0; +- if (flen > 6 && strncmp(r->filename, "proxy:", 6) == 0) { ++ if (to_proxyreq) { + /* it should be go on as an internal proxy request */ -+ if (r->args && *(ap_scan_vchar_obstext(r->args))) { + /* check if the proxy module is enabled, so +@@ -4749,7 +4799,7 @@ static int hook_uri2file(request_rec *r) + r->filename)); + return OK; + } +- else if ((skip = is_absolute_uri(r->filename, NULL)) > 0) { ++ else if (skip_absolute > 0) { + int n; + + /* it was finally rewritten to a remote URL */ +@@ -4757,7 +4807,7 @@ static int hook_uri2file(request_rec *r) + if (rulestatus != ACTION_NOESCAPE) { + rewritelog((r, 1, NULL, "escaping %s for redirect", + r->filename)); +- r->filename = escape_absolute_uri(r->pool, r->filename, skip); ++ r->filename = escape_absolute_uri(r->pool, r->filename, skip_absolute); + } + + /* append the QUERY_STRING part */ +@@ -4981,7 +5031,26 @@ static int hook_fixup(request_rec *r) + */ + rulestatus = apply_rewrite_list(r, dconf->rewriterules, dconf->directory); + if (rulestatus) { +- unsigned skip; ++ unsigned skip_absolute = is_absolute_uri(r->filename, NULL); ++ int to_proxyreq = 0; ++ int will_escape = 0; ++ ++ l = strlen(r->filename); ++ to_proxyreq = l > 6 && strncmp(r->filename, "proxy:", 6) == 0; ++ will_escape = skip_absolute && (rulestatus != ACTION_NOESCAPE); ++ ++ if (r->args ++ && !will_escape ++ && *(ap_scan_vchar_obstext(r->args))) { + /* + * We have a raw control character or a ' ' in r->args. + * Correct encoding was missed. @@ -206,12 +571,48 @@ index 38dbb24..c3937ad 100644 + "characters or spaces"); + return HTTP_FORBIDDEN; + } -+ + if (ACTION_STATUS == rulestatus) { int n = r->status; +@@ -4990,8 +5059,7 @@ static int hook_fixup(request_rec *r) + return n; + } + +- l = strlen(r->filename); +- if (l > 6 && strncmp(r->filename, "proxy:", 6) == 0) { ++ if (to_proxyreq) { + /* it should go on as an internal proxy request */ + + /* make sure the QUERY_STRING and +@@ -5015,7 +5083,7 @@ static int hook_fixup(request_rec *r) + "%s [OK]", r->filename)); + return OK; + } +- else if ((skip = is_absolute_uri(r->filename, NULL)) > 0) { ++ else if (skip_absolute > 0) { + /* it was finally rewritten to a remote URL */ + /* because we are in a per-dir context +@@ -5024,7 +5092,7 @@ static int hook_fixup(request_rec *r) + */ + if (dconf->baseurl != NULL) { + /* skip 'scheme://' */ +- cp = r->filename + skip; ++ cp = r->filename + skip_absolute; + + if ((cp = ap_strchr(cp, '/')) != NULL && *(++cp)) { + rewritelog((r, 2, dconf->directory, +@@ -5069,7 +5137,7 @@ static int hook_fixup(request_rec *r) + if (rulestatus != ACTION_NOESCAPE) { + rewritelog((r, 1, dconf->directory, "escaping %s for redirect", + r->filename)); +- r->filename = escape_absolute_uri(r->pool, r->filename, skip); ++ r->filename = escape_absolute_uri(r->pool, r->filename, skip_absolute); + } + + /* append the QUERY_STRING part */ diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c -index 058b03f..a529c02 100644 +index 6faabea..59396a8 100644 --- a/modules/proxy/mod_proxy_ajp.c +++ b/modules/proxy/mod_proxy_ajp.c @@ -69,6 +69,16 @@ static int proxy_ajp_canon(request_rec *r, char *url) @@ -253,7 +654,7 @@ index 3a28038..c599e1a 100644 if (path == NULL) return HTTP_BAD_REQUEST; diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c -index c1c591a..58a8c86 100644 +index 7da9bde..2cdc61e 100644 --- a/modules/proxy/mod_proxy_http.c +++ b/modules/proxy/mod_proxy_http.c @@ -90,6 +90,16 @@ static int proxy_http_canon(request_rec *r, char *url) @@ -294,3 +695,41 @@ index e005a94..f5e27d9 100644 } if (path == NULL) return HTTP_BAD_REQUEST; +diff --git a/server/gen_test_char.c b/server/gen_test_char.c +index 48ae6f4..6a153a3 100644 +--- a/server/gen_test_char.c ++++ b/server/gen_test_char.c +@@ -169,5 +169,15 @@ int main(int argc, char *argv[]) + + printf("\n};\n"); + ++ ++ printf( ++ "/* we assume the folks using this ensure 0 <= c < 256... which means\n" ++ " * you need a cast to (unsigned char) first, you can't just plug a\n" ++ " * char in here and get it to work, because if char is signed then it\n" ++ " * will first be sign extended.\n" ++ " */\n" ++ "#define TEST_CHAR(c, f) (test_char_table[(unsigned char)(c)] & (f))\n" ++ ); ++ + return 0; + } +diff --git a/server/util.c b/server/util.c +index 2a5dd04..1d82fd8 100644 +--- a/server/util.c ++++ b/server/util.c +@@ -74,13 +74,6 @@ + */ + #include "test_char.h" + +-/* we assume the folks using this ensure 0 <= c < 256... which means +- * you need a cast to (unsigned char) first, you can't just plug a +- * char in here and get it to work, because if char is signed then it +- * will first be sign extended. +- */ +-#define TEST_CHAR(c, f) (test_char_table[(unsigned char)(c)] & (f)) +- + /* Win32/NetWare/OS2 need to check for both forward and back slashes + * in ap_getparents() and ap_escape_url. + */ diff --git a/httpd-2.4.37-add-SNI-support.patch b/httpd-2.4.37-add-SNI-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..8b8d9ad9a4ad7f2a64049cd822344de4ac0e1ada --- /dev/null +++ b/httpd-2.4.37-add-SNI-support.patch @@ -0,0 +1,92 @@ +commit 4c0e27d7bfbf46f14dfbd5d888e56c64ad8c8de5 +Author: Tomas Korbar
+Date: Mon Sep 19 13:22:27 2022 +0200 + + Backport refactor of SNI support to httpd-2.4.37 + +diff --git a/modules/http2/mod_proxy_http2.c b/modules/http2/mod_proxy_http2.c +index a7e0dcd..31ccd32 100644 +--- a/modules/http2/mod_proxy_http2.c ++++ b/modules/http2/mod_proxy_http2.c +@@ -591,16 +591,6 @@ run_connect: + } + + if (!ctx->p_conn->data) { +- /* New conection: set a note on the connection what CN is +- * requested and what protocol we want */ +- if (ctx->p_conn->ssl_hostname) { +- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, ctx->owner, +- "set SNI to %s for (%s)", +- ctx->p_conn->ssl_hostname, +- ctx->p_conn->hostname); +- apr_table_setn(ctx->p_conn->connection->notes, +- "proxy-request-hostname", ctx->p_conn->ssl_hostname); +- } + if (ctx->is_ssl) { + apr_table_setn(ctx->p_conn->connection->notes, + "proxy-request-alpn-protos", "h2"); +diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c +index 1b7bb81..c1c591a 100644 +--- a/modules/proxy/mod_proxy_http.c ++++ b/modules/proxy/mod_proxy_http.c +@@ -2111,19 +2111,6 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker, + req->origin->keepalive = AP_CONN_CLOSE; + } + +- /* +- * On SSL connections set a note on the connection what CN is +- * requested, such that mod_ssl can check if it is requested to do +- * so. +- * +- * https://github.com/apache/httpd/commit/7d272e2628b4ae05f68cdc74b070707250896a34 +- */ +- if (backend->ssl_hostname) { +- apr_table_setn(backend->connection->notes, +- "proxy-request-hostname", +- backend->ssl_hostname); +- } +- + /* Step Four: Send the Request + * On the off-chance that we forced a 100-Continue as a + * kinda HTTP ping test, allow for retries +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index ec9a414..805820d 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -3261,6 +3261,16 @@ static int proxy_connection_create(const char *proxy_function, + backend_addr, conn->hostname); + return HTTP_INTERNAL_SERVER_ERROR; + } ++ if (conn->ssl_hostname) { ++ /* Set a note on the connection about what CN is requested, ++ * such that mod_ssl can check if it is requested to do so. ++ */ ++ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, conn->connection, ++ "%s: set SNI to %s for (%s)", proxy_function, ++ conn->ssl_hostname, conn->hostname); ++ apr_table_setn(conn->connection->notes, "proxy-request-hostname", ++ conn->ssl_hostname); ++ } + } + else { + /* TODO: See if this will break FTP */ +diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c +index 4e3875a..9b4280c 100644 +--- a/modules/ssl/ssl_engine_io.c ++++ b/modules/ssl/ssl_engine_io.c +@@ -1273,7 +1273,6 @@ static apr_status_t ssl_io_filter_handshake(ssl_filter_ctx_t *filter_ctx) + ((dc->proxy->ssl_check_peer_cn != FALSE) || + (dc->proxy->ssl_check_peer_name == TRUE)) && + hostname_note) { +- apr_table_unset(c->notes, "proxy-request-hostname"); + if (!cert + || modssl_X509_match_name(c->pool, cert, hostname_note, + TRUE, server) == FALSE) { +@@ -1290,7 +1289,6 @@ static apr_status_t ssl_io_filter_handshake(ssl_filter_ctx_t *filter_ctx) + + hostname = ssl_var_lookup(NULL, server, c, NULL, + "SSL_CLIENT_S_DN_CN"); +- apr_table_unset(c->notes, "proxy-request-hostname"); + + /* Do string match or simplest wildcard match if that + * fails. */ diff --git a/httpd.spec b/httpd.spec index 6f96ef219ba5090827ff0451ea02a9e2016a5965..43bf3807d794bcc89a4b5f4f7d703e2f9f9067a5 100644 --- a/httpd.spec +++ b/httpd.spec @@ -1,4 +1,4 @@ -%define anolis_release .0.2 +%define anolis_release .0.1 %define contentdir %{_datadir}/httpd %define docroot /var/www %define suexec_caller apache @@ -14,7 +14,7 @@ Summary: Apache HTTP Server Name: httpd Version: 2.4.37 -Release: 51%{anolis_release}%{?dist}.5 +Release: 56%{anolis_release}%{?dist}.6 URL: https://httpd.apache.org/ Source0: https://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2 Source2: httpd.logrotate @@ -164,6 +164,8 @@ Patch88: httpd-2.4.37-r1845768+.patch Patch89: httpd-2.4.37-r1862410.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1984828 Patch90: httpd-2.4.37-hcheck-mem-issues.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2017543 +Patch91: httpd-2.4.37-add-SNI-support.patch # Security fixes Patch200: httpd-2.4.37-r1851471.patch @@ -270,7 +272,7 @@ Provides: mod_dav = %{version}-%{release}, httpd-suexec = %{version}-%{release} Provides: httpd-mmn = %{mmn}, httpd-mmn = %{mmnisa} Requires: httpd-tools = %{version}-%{release} Requires: httpd-filesystem = %{version}-%{release} -Requires: mod_http2 +Requires: mod_http2 >= 1.15.7-5 Requires(pre): httpd-filesystem Requires(preun): systemd-units Requires(postun): systemd-units @@ -334,7 +336,7 @@ Epoch: 1 BuildRequires: openssl-devel Requires(pre): httpd-filesystem Requires: httpd = 0:%{version}-%{release}, httpd-mmn = %{mmnisa} -Requires: sscg >= 2.2.0 +Requires: sscg >= 3.0.0-7, /usr/bin/hostname Obsoletes: stronghold-mod_ssl # Require an OpenSSL which supports PROFILE=SYSTEM Conflicts: openssl-libs < 1:1.0.1h-4 @@ -433,6 +435,7 @@ interface for storing and accessing per-user session data. %patch88 -p1 -b .r1845768+ %patch89 -p1 -b .r1862410 %patch90 -p1 -b .hcheck-mem-issues +%patch91 -p1 -b .SNI %patch200 -p1 -b .r1851471 %patch201 -p1 -b .CVE-2019-0211 @@ -984,26 +987,40 @@ rm -rf $RPM_BUILD_ROOT %{_rpmconfigdir}/macros.d/macros.httpd %changelog -* Fri Apr 28 2023 guochuang -2.4.37-51.0.2.5 -- add patch for CVE-2023-27522 - -* Fri Apr 07 2023 zhangbinchen - 2.4.37-51.0.1.5 +* Fri Jun 16 2023 zhangbinchen - 2.4.37-56.0.1.6 - Rebrand for Anolis OS(Binchen Zhang) - Requires system-logos-httpd(Binchen Zhang) - Support loongarch64 platform(Liwei Ge) +- add patch for CVE-2023-27522(guo.chuang@zte.com.cn) + +* Thu Apr 27 2023 Luboš Uhliarik - 2.4.37-56.6 +- Resolves: #2190133 - mod_rewrite regression with CVE-2023-25690 -* Sat Mar 18 2023 Luboš Uhliarik - 2.4.37-51.5 -- Resolves: #2177747 - CVE-2023-25690 httpd:2.4/httpd: HTTP request splitting +* Sat Mar 18 2023 Luboš Uhliarik - 2.4.37-56.4 +- Resolves: #2177748 - CVE-2023-25690 httpd:2.4/httpd: HTTP request splitting with mod_rewrite and mod_proxy -* Tue Jan 31 2023 Luboš Uhliarik - 2.4.37-51.1 -- Resolves: #2165967 - prevent sscg creating /dhparams.pem -- Resolves: #2165976 - CVE-2006-20001 httpd: mod_dav: out-of-bounds read/write +* Tue Jan 31 2023 Luboš Uhliarik - 2.4.37-56 +- Resolves: #2162499 - CVE-2006-20001 httpd: mod_dav: out-of-bounds read/write of zero byte -- Resolves: #2165977 - CVE-2022-37436 httpd: mod_proxy: HTTP response splitting -- Resolves: #2165978 - CVE-2022-36760 httpd: mod_proxy_ajp: Possible request +- Resolves: #2162485 - CVE-2022-37436 httpd: mod_proxy: HTTP response splitting +- Resolves: #2162509 - CVE-2022-36760 httpd: mod_proxy_ajp: Possible request smuggling +* Thu Jan 26 2023 Luboš Uhliarik - 2.4.37-55 +- Resolves: #2155961 - prevent sscg creating /dhparams.pem + +* Thu Dec 08 2022 Luboš Uhliarik - 2.4.37-54 +- Resolves: #2095650 - Dependency from mod_http2 on httpd broken + +* Wed Nov 09 2022 Luboš Uhliarik - 2.4.37-53 +- Resolves: #2050888 - httpd with SSL fails to start unless hostname command + was installed + +* Mon Sep 19 2022 Tomas Korbar - 2.4.37-52 +- Add the SNI support in mod_proxy_wstunnel module for Apache httpd +- Resolves: rhbz#2017543 + * Mon Jul 25 2022 Luboš Uhliarik - 2.4.37-51 - Resolves: #2097015 - CVE-2022-28614 httpd:2.4/httpd: out-of-bounds read via ap_rwrite()