File apache2-CVE-2021-44224-1.patch of Package apache2.27541
Index: httpd-2.4.33/modules/proxy/mod_proxy.c
===================================================================
--- httpd-2.4.33.orig/modules/proxy/mod_proxy.c 2022-01-05 09:04:47.845745324 +0100
+++ httpd-2.4.33/modules/proxy/mod_proxy.c 2022-01-05 09:42:10.490493313 +0100
@@ -1724,7 +1724,8 @@ static const char *
const apr_array_header_t *arr;
const apr_table_entry_t *elts;
int i;
- int use_regex = is_regex;
+ unsigned int worker_type = (is_regex) ? AP_PROXY_WORKER_IS_MATCH
+ : AP_PROXY_WORKER_IS_PREFIX;
unsigned int flags = 0;
const char *err;
@@ -1740,7 +1741,7 @@ static const char *
if (is_regex) {
return "ProxyPassMatch invalid syntax ('~' usage).";
}
- use_regex = 1;
+ worker_type = AP_PROXY_WORKER_IS_MATCH;
continue;
}
f = word;
@@ -1791,7 +1792,7 @@ static const char *
dconf->alias_set = 1;
new = dconf->alias;
if (apr_fnmatch_test(f)) {
- use_regex = 1;
+ worker_type = AP_PROXY_WORKER_IS_MATCH;
}
}
/* if per server, add to the alias array */
@@ -1802,7 +1803,7 @@ static const char *
new->fake = apr_pstrdup(cmd->pool, f);
new->real = apr_pstrdup(cmd->pool, ap_proxy_de_socketfy(cmd->pool, r));
new->flags = flags;
- if (use_regex) {
+ if (worker_type & AP_PROXY_WORKER_IS_MATCH) {
new->regex = ap_pregcomp(cmd->pool, f, AP_REG_EXTENDED);
if (new->regex == NULL)
return "Regular expression could not be compiled.";
@@ -1826,7 +1827,7 @@ static const char *
* cannot be parsed anyway with apr_uri_parse later on in
* ap_proxy_define_balancer / ap_proxy_update_balancer
*/
- if (use_regex) {
+ if (worker_type & AP_PROXY_WORKER_IS_MATCH) {
fake_copy = NULL;
}
else {
@@ -1849,10 +1850,13 @@ static const char *
new->balancer = balancer;
}
else {
- proxy_worker *worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, ap_proxy_de_socketfy(cmd->pool, r));
int reuse = 0;
+ proxy_worker *worker = ap_proxy_get_worker_ex(cmd->temp_pool, NULL,
+ conf, new->real,
+ worker_type);
if (!worker) {
- const char *err = ap_proxy_define_worker(cmd->pool, &worker, NULL, conf, r, 0);
+ const char *err = ap_proxy_define_worker_ex(cmd->pool, &worker, NULL,
+ conf, r, worker_type);
if (err)
return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL);
@@ -2329,7 +2333,8 @@ static const char *add_member(cmd_parms
}
/* Try to find existing worker */
- worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, ap_proxy_de_socketfy(cmd->temp_pool, name));
+ worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf,
+ ap_proxy_de_socketfy(cmd->temp_pool, name));
if (!worker) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01147)
"Defining worker '%s' for balancer '%s'",
@@ -2378,6 +2383,7 @@ static const char *
char *word, *val;
proxy_balancer *balancer = NULL;
proxy_worker *worker = NULL;
+ unsigned int worker_type = 0;
int in_proxy_section = 0;
/* XXX: Should this be NOT_IN_DIRECTORY|NOT_IN_FILES? */
const char *err = ap_check_cmd_context(cmd, NOT_IN_HTACCESS);
@@ -2394,6 +2400,13 @@ static const char *
name = ap_getword_conf(cmd->temp_pool, &pargs);
if ((word = ap_strchr(name, '>')))
*word = '\0';
+ if (strncasecmp(cmd->directive->parent->directive + 6,
+ "Match", 5) == 0) {
+ worker_type = AP_PROXY_WORKER_IS_MATCH;
+ }
+ else {
+ worker_type = AP_PROXY_WORKER_IS_PREFIX;
+ }
in_proxy_section = 1;
}
else {
@@ -2418,11 +2431,13 @@ static const char *
}
}
else {
- worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, ap_proxy_de_socketfy(cmd->temp_pool, name));
+ worker = ap_proxy_get_worker_ex(cmd->temp_pool, NULL, conf,
+ ap_proxy_de_socketfy(cmd->temp_pool, name),
+ worker_type);
if (!worker) {
if (in_proxy_section) {
- err = ap_proxy_define_worker(cmd->pool, &worker, NULL,
- conf, name, 0);
+ err = ap_proxy_define_worker_ex(cmd->pool, &worker, NULL,
+ conf, name, worker_type);
if (err)
return apr_pstrcat(cmd->temp_pool, "ProxySet ",
err, NULL);
@@ -2477,6 +2492,7 @@ static const char *proxysection(cmd_parm
proxy_balancer *balancer = NULL;
proxy_worker *worker = NULL;
+ unsigned int worker_type = AP_PROXY_WORKER_IS_PREFIX;
const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_CONTEXT);
proxy_server_conf *sconf =
(proxy_server_conf *) ap_get_module_config(cmd->server->module_config, &proxy_module);
@@ -2514,6 +2530,8 @@ static const char *proxysection(cmd_parm
if (!r) {
return "Regex could not be compiled";
}
+
+ worker_type = AP_PROXY_WORKER_IS_MATCH;
}
/* initialize our config and fetch it */
@@ -2560,11 +2578,12 @@ static const char *proxysection(cmd_parm
}
}
else {
- worker = ap_proxy_get_worker(cmd->temp_pool, NULL, sconf,
- ap_proxy_de_socketfy(cmd->temp_pool, (char*)conf->p));
+ worker = ap_proxy_get_worker_ex(cmd->temp_pool, NULL, sconf,
+ ap_proxy_de_socketfy(cmd->temp_pool, conf->p),
+ worker_type);
if (!worker) {
- err = ap_proxy_define_worker(cmd->pool, &worker, NULL,
- sconf, conf->p, 0);
+ err = ap_proxy_define_worker_ex(cmd->pool, &worker, NULL, sconf,
+ conf->p, worker_type);
if (err)
return apr_pstrcat(cmd->temp_pool, thiscmd->name,
" ", err, NULL);
Index: httpd-2.4.33/modules/proxy/mod_proxy.h
===================================================================
--- httpd-2.4.33.orig/modules/proxy/mod_proxy.h 2022-01-05 09:04:47.745744754 +0100
+++ httpd-2.4.33/modules/proxy/mod_proxy.h 2022-01-05 09:04:47.873745482 +0100
@@ -703,8 +703,29 @@ typedef __declspec(dllimport) const char
PROXY_DECLARE(char *) ap_proxy_worker_name(apr_pool_t *p,
proxy_worker *worker);
+/* Bitmask for ap_proxy_{define,get}_worker_ex(). */
+#define AP_PROXY_WORKER_IS_PREFIX (1u << 0)
+#define AP_PROXY_WORKER_IS_MATCH (1u << 1)
+#define AP_PROXY_WORKER_IS_MALLOCED (1u << 2)
+
+/**
+ * Get the worker from proxy configuration, looking for either PREFIXED or
+ * MATCHED or both types of workers according to given mask
+ * @param p memory pool used for finding worker
+ * @param balancer the balancer that the worker belongs to
+ * @param conf current proxy server configuration
+ * @param url url to find the worker from
+ * @param mask bitmask of AP_PROXY_WORKER_IS_*
+ * @return proxy_worker or NULL if not found
+ */
+PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker_ex(apr_pool_t *p,
+ proxy_balancer *balancer,
+ proxy_server_conf *conf,
+ const char *url,
+ unsigned int mask);
+
/**
- * Get the worker from proxy configuration
+ * Get the worker from proxy configuration, both types
* @param p memory pool used for finding worker
* @param balancer the balancer that the worker belongs to
* @param conf current proxy server configuration
@@ -715,7 +736,26 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_g
proxy_balancer *balancer,
proxy_server_conf *conf,
const char *url);
+
/**
+ * Define and Allocate space for the worker to proxy configuration, of either
+ * PREFIXED or MATCHED type according to given mask
+ * @param p memory pool to allocate worker from
+ * @param worker the new worker
+ * @param balancer the balancer that the worker belongs to
+ * @param conf current proxy server configuration
+ * @param url url containing worker name
+ * @param mask bitmask of AP_PROXY_WORKER_IS_*
+ * @return error message or NULL if successful (*worker is new worker)
+ */
+PROXY_DECLARE(char *) ap_proxy_define_worker_ex(apr_pool_t *p,
+ proxy_worker **worker,
+ proxy_balancer *balancer,
+ proxy_server_conf *conf,
+ const char *url,
+ unsigned int mask);
+
+ /**
* Define and Allocate space for the worker to proxy configuration
* @param p memory pool to allocate worker from
* @param worker the new worker
@@ -724,6 +764,7 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_g
* @param url url containing worker name
* @param do_malloc true if shared struct should be malloced
* @return error message or NULL if successful (*worker is new worker)
+ * @deprecated Replaced by ap_proxy_define_worker_ex()
*/
PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p,
proxy_worker **worker,
Index: httpd-2.4.33/modules/proxy/proxy_util.c
===================================================================
--- httpd-2.4.33.orig/modules/proxy/proxy_util.c 2022-01-05 09:04:47.845745324 +0100
+++ httpd-2.4.33/modules/proxy/proxy_util.c 2022-01-05 10:26:11.597464406 +0100
@@ -19,6 +19,7 @@
#include "ap_mpm.h"
#include "scoreboard.h"
#include "apr_version.h"
+#include "apr_strings.h"
#include "apr_hash.h"
#include "proxy_util.h"
#include "ajp.h"
@@ -1503,10 +1504,11 @@ PROXY_DECLARE(char *) ap_proxy_worker_na
return apr_pstrcat(p, "unix:", worker->s->uds_path, "|", worker->s->name, NULL);
}
-PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
- proxy_balancer *balancer,
- proxy_server_conf *conf,
- const char *url)
+PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker_ex(apr_pool_t *p,
+ proxy_balancer *balancer,
+ proxy_server_conf *conf,
+ const char *url,
+ unsigned int mask)
{
proxy_worker *worker;
proxy_worker *max_worker = NULL;
@@ -1532,6 +1534,11 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_g
url_length = strlen(url);
url_copy = apr_pstrmemdup(p, url, url_length);
+ /* Default to lookup for both _PREFIX and _MATCH workers */
+ if (!(mask & (AP_PROXY_WORKER_IS_PREFIX | AP_PROXY_WORKER_IS_MATCH))) {
+ mask |= AP_PROXY_WORKER_IS_PREFIX | AP_PROXY_WORKER_IS_MATCH;
+ }
+
/*
* We need to find the start of the path and
* therefore we know the length of the scheme://hostname/
@@ -1565,7 +1572,7 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_g
if ( ((worker_name_length = strlen(worker->s->name)) <= url_length)
&& (worker_name_length >= min_match)
&& (worker_name_length > max_match)
- && (strncmp(url_copy, worker->s->name, worker_name_length) == 0) ) {
+ && ((mask & AP_PROXY_WORKER_IS_PREFIX) && strncmp(url_copy, worker->s->name, worker_name_length) == 0) ) {
max_worker = worker;
max_match = worker_name_length;
}
@@ -1577,7 +1584,7 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_g
if ( ((worker_name_length = strlen(worker->s->name)) <= url_length)
&& (worker_name_length >= min_match)
&& (worker_name_length > max_match)
- && (strncmp(url_copy, worker->s->name, worker_name_length) == 0) ) {
+ && ((mask & AP_PROXY_WORKER_IS_PREFIX) && strncmp(url_copy, worker->s->name, worker_name_length) == 0) ) {
max_worker = worker;
max_match = worker_name_length;
}
@@ -1587,6 +1594,14 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_g
return max_worker;
}
+PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
+ proxy_balancer *balancer,
+ proxy_server_conf *conf,
+ const char *url)
+{
+ return ap_proxy_get_worker_ex(p, balancer, conf, url, 0);
+}
+
/*
* To create a worker from scratch first we define the
* specifics of the worker; this is all local data.
@@ -1594,46 +1609,86 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_g
* shared. This allows for dynamic addition during
* config and runtime.
*/
-PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p,
+PROXY_DECLARE(char *) ap_proxy_define_worker_ex(apr_pool_t *p,
proxy_worker **worker,
proxy_balancer *balancer,
proxy_server_conf *conf,
const char *url,
- int do_malloc)
+ unsigned int mask)
{
- int rv;
- apr_uri_t uri, urisock;
+ apr_status_t rv;
proxy_worker_shared *wshared;
- char *ptr, *sockpath = NULL;
+ const char *ptr = NULL, *sockpath = NULL, *pdollars = NULL;
+ apr_port_t port_of_scheme;
+ apr_uri_t uri;
/*
* Look to see if we are using UDS:
* require format: unix:/path/foo/bar.sock|http://ignored/path2/
* This results in talking http to the socket at /path/foo/bar.sock
*/
- ptr = ap_strchr((char *)url, '|');
- if (ptr) {
- *ptr = '\0';
- rv = apr_uri_parse(p, url, &urisock);
- if (rv == APR_SUCCESS && !strcasecmp(urisock.scheme, "unix")) {
- sockpath = ap_runtime_dir_relative(p, urisock.path);;
- url = ptr+1; /* so we get the scheme for the uds */
+ if (!ap_cstr_casecmpn(url, "unix:", 5)
+ && (ptr = ap_strchr_c(url + 5, '|'))) {
+ rv = apr_uri_parse(p, apr_pstrmemdup(p, url, ptr - url), &uri);
+ if (rv == APR_SUCCESS) {
+ sockpath = ap_runtime_dir_relative(p, uri.path);;
+ ptr++; /* so we get the scheme for the uds */
}
else {
- *ptr = '|';
+ ptr = url;
}
}
- rv = apr_uri_parse(p, url, &uri);
+ else {
+ ptr = url;
+ }
+ if (mask & AP_PROXY_WORKER_IS_MATCH) {
+ /* apr_uri_parse() will accept the '$' sign anywhere in the URL but
+ * in the :port part, and we don't want scheme://host:port$1$2/path
+ * to fail (e.g. "ProxyPassMatch ^/(a|b)(/.*)? http://host:port$2").
+ * So we trim all the $n from the :port and prepend them in uri.path
+ * afterward for apr_uri_unparse() to restore the original URL below.
+ */
+#define IS_REF(x) (x[0] == '$' && apr_isdigit(x[1]))
+ const char *pos = ap_strstr_c(ptr, "://");
+ if (pos) {
+ pos += 3;
+ while (*pos && *pos != ':' && *pos != '/') {
+ pos++;
+ }
+ if (*pos == ':') {
+ pos++;
+ while (*pos && !IS_REF(pos) && *pos != '/') {
+ pos++;
+ }
+ if (IS_REF(pos)) {
+ struct iovec vec[2];
+ const char *path = pos + 2;
+ while (*path && *path != '/') {
+ path++;
+ }
+ pdollars = apr_pstrmemdup(p, pos, path - pos);
+ vec[0].iov_base = (void *)ptr;
+ vec[0].iov_len = pos - ptr;
+ vec[1].iov_base = (void *)path;
+ vec[1].iov_len = strlen(path);
+ ptr = apr_pstrcatv(p, vec, 2, NULL);
+ }
+ }
+ }
+#undef IS_REF
+ }
+ /* Normalize the url (worker name) */
+ rv = apr_uri_parse(p, ptr, &uri);
if (rv != APR_SUCCESS) {
return apr_pstrcat(p, "Unable to parse URL: ", url, NULL);
}
if (!uri.scheme) {
return apr_pstrcat(p, "URL must be absolute!: ", url, NULL);
}
- /* allow for unix:/path|http: */
if (!uri.hostname) {
if (sockpath) {
+ /* allow for unix:/path|http: */
uri.hostname = "localhost";
}
else {
@@ -1644,6 +1699,16 @@ PROXY_DECLARE(char *) ap_proxy_define_wo
ap_str_tolower(uri.hostname);
}
ap_str_tolower(uri.scheme);
+ port_of_scheme = ap_proxy_port_of_scheme(uri.scheme);
+ if (uri.port && uri.port == port_of_scheme) {
+ uri.port = 0;
+ }
+ if (pdollars) {
+ /* Restore/prepend pdollars into the path. */
+ uri.path = apr_pstrcat(p, pdollars, uri.path, NULL);
+ }
+ ptr = apr_uri_unparse(p, &uri, APR_URI_UNP_REVEALPASSWORD);
+
/*
* Workers can be associated w/ balancers or on their
* own; ie: the generic reverse-proxy or a worker
@@ -1667,23 +1732,17 @@ PROXY_DECLARE(char *) ap_proxy_define_wo
/* we need to allocate space here */
*worker = apr_palloc(p, sizeof(proxy_worker));
}
-
memset(*worker, 0, sizeof(proxy_worker));
+
/* right here we just want to tuck away the worker info.
* if called during config, we don't have shm setup yet,
* so just note the info for later. */
- if (do_malloc)
+ if (mask & AP_PROXY_WORKER_IS_MALLOCED)
wshared = ap_malloc(sizeof(proxy_worker_shared)); /* will be freed ap_proxy_share_worker */
else
wshared = apr_palloc(p, sizeof(proxy_worker_shared));
-
memset(wshared, 0, sizeof(proxy_worker_shared));
- wshared->port = (uri.port ? uri.port : ap_proxy_port_of_scheme(uri.scheme));
- if (uri.port && uri.port == ap_proxy_port_of_scheme(uri.scheme)) {
- uri.port = 0;
- }
- ptr = apr_uri_unparse(p, &uri, APR_URI_UNP_REVEALPASSWORD);
if (PROXY_STRNCPY(wshared->name, ptr) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, APLOGNO(02808)
"Alert! worker name (%s) too long; truncated to: %s", ptr, wshared->name);
@@ -1700,6 +1759,7 @@ PROXY_DECLARE(char *) ap_proxy_define_wo
"worker hostname (%s) too long; truncated for legacy modules that do not use "
"proxy_worker_shared->hostname_ex: %s", uri.hostname, wshared->hostname);
}
+ wshared->port = (uri.port) ? uri.port : port_of_scheme;
wshared->flush_packets = flush_off;
wshared->flush_wait = PROXY_FLUSH_WAIT;
wshared->is_address_reusable = 1;
@@ -1710,7 +1770,7 @@ PROXY_DECLARE(char *) ap_proxy_define_wo
wshared->smax = -1;
wshared->hash.def = ap_proxy_hashfunc(wshared->name, PROXY_HASHFUNC_DEFAULT);
wshared->hash.fnv = ap_proxy_hashfunc(wshared->name, PROXY_HASHFUNC_FNV);
- wshared->was_malloced = (do_malloc != 0);
+ wshared->was_malloced = (mask & AP_PROXY_WORKER_IS_MALLOCED) != 0;
if (sockpath) {
if (PROXY_STRNCPY(wshared->uds_path, sockpath) != APR_SUCCESS) {
return apr_psprintf(p, "worker uds path (%s) too long", sockpath);
@@ -1730,9 +1790,37 @@ PROXY_DECLARE(char *) ap_proxy_define_wo
(*worker)->balancer = balancer;
(*worker)->s = wshared;
+ if (mask & AP_PROXY_WORKER_IS_MATCH) {
+ if (ap_strchr_c((*worker)->s->name, '$')) {
+ /* Before AP_PROXY_WORKER_IS_MATCH (< 2.4.47), a regex worker
+ * with dollar substitution was never matched against the actual
+ * URL thus the request fell through the generic worker. To avoid
+ * dns and connection reuse compat issues, let's disable connection
+ * reuse by default, it can still be overwritten by an explicit
+ * enablereuse=on.
+ */
+ (*worker)->s->disablereuse = 1;
+ }
+ }
+
+
return NULL;
}
+PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p,
+ proxy_worker **worker,
+ proxy_balancer *balancer,
+ proxy_server_conf *conf,
+ const char *url,
+ int do_malloc)
+{
+ return ap_proxy_define_worker_ex(p, worker, balancer, conf, url,
+ AP_PROXY_WORKER_IS_PREFIX |
+ (do_malloc ? AP_PROXY_WORKER_IS_MALLOCED
+ : 0));
+}
+
+
/*
* Create an already defined worker and free up memory
*/