new version 2.4.62

Resolves: RHEL-52724 - Regression introduced by CVE-2024-38474 fix
This commit is contained in:
Luboš Uhliarik 2024-08-04 00:24:51 +02:00
parent 7770a807d3
commit 46fa0eee6d
11 changed files with 280 additions and 2812 deletions

1
.gitignore vendored
View File

@ -44,3 +44,4 @@ x86_64
/httpd-2.4.53.tar.bz2.asc /httpd-2.4.53.tar.bz2.asc
/httpd-2.4.57.tar.bz2.asc /httpd-2.4.57.tar.bz2.asc
/httpd-2.4.59.tar.bz2.asc /httpd-2.4.59.tar.bz2.asc
/httpd-2.4.62.tar.bz2.asc

View File

@ -1,249 +0,0 @@
diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
index 376b8ab..950dc2b 100644
--- a/modules/ssl/ssl_engine_init.c
+++ b/modules/ssl/ssl_engine_init.c
@@ -887,6 +887,13 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s,
SSL_CTX_set_options(ctx, SSL_OP_IGNORE_UNEXPECTED_EOF);
}
#endif
+
+#ifdef SSL_OP_NO_RENEGOTIATION
+ /* For server-side SSL_CTX, disable renegotiation by default.. */
+ if (!mctx->pkp) {
+ SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION);
+ }
+#endif
return APR_SUCCESS;
}
@@ -908,6 +915,14 @@ static void ssl_init_ctx_session_cache(server_rec *s,
}
}
+#ifdef SSL_OP_NO_RENEGOTIATION
+/* OpenSSL-level renegotiation protection. */
+#define MODSSL_BLOCKS_RENEG (0)
+#else
+/* mod_ssl-level renegotiation protection. */
+#define MODSSL_BLOCKS_RENEG (1)
+#endif
+
static void ssl_init_ctx_callbacks(server_rec *s,
apr_pool_t *p,
apr_pool_t *ptemp,
@@ -921,7 +936,13 @@ static void ssl_init_ctx_callbacks(server_rec *s,
SSL_CTX_set_tmp_dh_callback(ctx, ssl_callback_TmpDH);
#endif
- SSL_CTX_set_info_callback(ctx, ssl_callback_Info);
+ /* The info callback is used for debug-level tracing. For OpenSSL
+ * versions where SSL_OP_NO_RENEGOTIATION is not available, the
+ * callback is also used to prevent use of client-initiated
+ * renegotiation. Enable it in either case. */
+ if (APLOGdebug(s) || MODSSL_BLOCKS_RENEG) {
+ SSL_CTX_set_info_callback(ctx, ssl_callback_Info);
+ }
#ifdef HAVE_TLS_ALPN
SSL_CTX_set_alpn_select_cb(ctx, ssl_callback_alpn_select, NULL);
diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c
index b91f784..9c7d216 100644
--- a/modules/ssl/ssl_engine_io.c
+++ b/modules/ssl/ssl_engine_io.c
@@ -208,11 +208,13 @@ static int bio_filter_out_write(BIO *bio, const char *in, int inl)
BIO_clear_retry_flags(bio);
+#ifndef SSL_OP_NO_RENEGOTIATION
/* Abort early if the client has initiated a renegotiation. */
if (outctx->filter_ctx->config->reneg_state == RENEG_ABORT) {
outctx->rc = APR_ECONNABORTED;
return -1;
}
+#endif
ap_log_cerror(APLOG_MARK, APLOG_TRACE6, 0, outctx->c,
"bio_filter_out_write: %i bytes", inl);
@@ -473,11 +475,13 @@ static int bio_filter_in_read(BIO *bio, char *in, int inlen)
BIO_clear_retry_flags(bio);
+#ifndef SSL_OP_NO_RENEGOTIATION
/* Abort early if the client has initiated a renegotiation. */
if (inctx->filter_ctx->config->reneg_state == RENEG_ABORT) {
inctx->rc = APR_ECONNABORTED;
return -1;
}
+#endif
if (!inctx->bb) {
inctx->rc = APR_EOF;
diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c
index fe0496f..fa1b3a8 100644
--- a/modules/ssl/ssl_engine_kernel.c
+++ b/modules/ssl/ssl_engine_kernel.c
@@ -992,7 +992,7 @@ static int ssl_hook_Access_classic(request_rec *r, SSLSrvConfigRec *sc, SSLDirCo
/* Toggle the renegotiation state to allow the new
* handshake to proceed. */
- sslconn->reneg_state = RENEG_ALLOW;
+ modssl_set_reneg_state(sslconn, RENEG_ALLOW);
SSL_renegotiate(ssl);
SSL_do_handshake(ssl);
@@ -1019,7 +1019,7 @@ static int ssl_hook_Access_classic(request_rec *r, SSLSrvConfigRec *sc, SSLDirCo
*/
SSL_peek(ssl, peekbuf, 0);
- sslconn->reneg_state = RENEG_REJECT;
+ modssl_set_reneg_state(sslconn, RENEG_REJECT);
if (!SSL_is_init_finished(ssl)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02261)
@@ -1078,7 +1078,7 @@ static int ssl_hook_Access_modern(request_rec *r, SSLSrvConfigRec *sc, SSLDirCon
(sc->server->auth.verify_mode != SSL_CVERIFY_UNSET)) {
int vmode_inplace, vmode_needed;
int change_vmode = FALSE;
- int old_state, n, rc;
+ int n, rc;
vmode_inplace = SSL_get_verify_mode(ssl);
vmode_needed = SSL_VERIFY_NONE;
@@ -1180,8 +1180,6 @@ static int ssl_hook_Access_modern(request_rec *r, SSLSrvConfigRec *sc, SSLDirCon
return HTTP_FORBIDDEN;
}
- old_state = sslconn->reneg_state;
- sslconn->reneg_state = RENEG_ALLOW;
modssl_set_app_data2(ssl, r);
SSL_do_handshake(ssl);
@@ -1191,7 +1189,6 @@ static int ssl_hook_Access_modern(request_rec *r, SSLSrvConfigRec *sc, SSLDirCon
*/
SSL_peek(ssl, peekbuf, 0);
- sslconn->reneg_state = old_state;
modssl_set_app_data2(ssl, NULL);
/*
@@ -2263,8 +2260,8 @@ static void log_tracing_state(const SSL *ssl, conn_rec *c,
/*
* This callback function is executed while OpenSSL processes the SSL
* handshake and does SSL record layer stuff. It's used to trap
- * client-initiated renegotiations, and for dumping everything to the
- * log.
+ * client-initiated renegotiations (where SSL_OP_NO_RENEGOTIATION is
+ * not available), and for dumping everything to the log.
*/
void ssl_callback_Info(const SSL *ssl, int where, int rc)
{
@@ -2276,14 +2273,12 @@ void ssl_callback_Info(const SSL *ssl, int where, int rc)
return;
}
- /* With TLS 1.3 this callback may be called multiple times on the first
- * negotiation, so the below logic to detect renegotiations can't work.
- * Fortunately renegotiations are forbidden starting with TLS 1.3, and
- * this is enforced by OpenSSL so there's nothing to be done here.
- */
-#if SSL_HAVE_PROTOCOL_TLSV1_3
- if (SSL_version(ssl) < TLS1_3_VERSION)
-#endif
+#ifndef SSL_OP_NO_RENEGOTIATION
+ /* With OpenSSL < 1.1.1 (implying TLS v1.2 or earlier), this
+ * callback is used to block client-initiated renegotiation. With
+ * TLSv1.3 it is unnecessary since renegotiation is forbidden at
+ * protocol level. Otherwise (TLSv1.2 with OpenSSL >=1.1.1),
+ * SSL_OP_NO_RENEGOTIATION is used to block renegotiation. */
{
SSLConnRec *sslconn;
@@ -2308,6 +2303,7 @@ void ssl_callback_Info(const SSL *ssl, int where, int rc)
sslconn->reneg_state = RENEG_REJECT;
}
}
+#endif
s = mySrvFromConn(c);
if (s && APLOGdebug(s)) {
diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h
index 859e932..25d79ce 100644
--- a/modules/ssl/ssl_private.h
+++ b/modules/ssl/ssl_private.h
@@ -549,6 +549,16 @@ typedef struct {
apr_time_t source_mtime;
} ssl_asn1_t;
+typedef enum {
+ RENEG_INIT = 0, /* Before initial handshake */
+ RENEG_REJECT, /* After initial handshake; any client-initiated
+ * renegotiation should be rejected */
+ RENEG_ALLOW, /* A server-initiated renegotiation is taking
+ * place (as dictated by configuration) */
+ RENEG_ABORT /* Renegotiation initiated by client, abort the
+ * connection */
+} modssl_reneg_state;
+
/**
* Define the mod_ssl per-module configuration structure
* (i.e. the global configuration for each httpd process)
@@ -580,18 +590,13 @@ typedef struct {
NON_SSL_SET_ERROR_MSG /* Need to set the error message */
} non_ssl_request;
- /* Track the handshake/renegotiation state for the connection so
- * that all client-initiated renegotiations can be rejected, as a
- * partial fix for CVE-2009-3555. */
- enum {
- RENEG_INIT = 0, /* Before initial handshake */
- RENEG_REJECT, /* After initial handshake; any client-initiated
- * renegotiation should be rejected */
- RENEG_ALLOW, /* A server-initiated renegotiation is taking
- * place (as dictated by configuration) */
- RENEG_ABORT /* Renegotiation initiated by client, abort the
- * connection */
- } reneg_state;
+#ifndef SSL_OP_NO_RENEGOTIATION
+ /* For OpenSSL < 1.1.1, track the handshake/renegotiation state
+ * for the connection to block client-initiated renegotiations.
+ * For OpenSSL >=1.1.1, the SSL_OP_NO_RENEGOTIATION flag is used in
+ * the SSL * options state with equivalent effect. */
+ modssl_reneg_state reneg_state;
+#endif
server_rec *server;
SSLDirConfigRec *dc;
@@ -1198,6 +1203,9 @@ int ssl_is_challenge(conn_rec *c, const char *servername,
* the configured ENGINE. */
int modssl_is_engine_id(const char *name);
+/* Set the renegotation state for connection. */
+void modssl_set_reneg_state(SSLConnRec *sslconn, modssl_reneg_state state);
+
#endif /* SSL_PRIVATE_H */
/** @} */
diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c
index 44930b7..8bd9c8a 100644
--- a/modules/ssl/ssl_util_ssl.c
+++ b/modules/ssl/ssl_util_ssl.c
@@ -612,3 +612,19 @@ cleanup:
}
return rv;
}
+
+void modssl_set_reneg_state(SSLConnRec *sslconn, modssl_reneg_state state)
+{
+#ifdef SSL_OP_NO_RENEGOTIATION
+ switch (state) {
+ case RENEG_ALLOW:
+ SSL_clear_options(sslconn->ssl, SSL_OP_NO_RENEGOTIATION);
+ break;
+ default:
+ SSL_set_options(sslconn->ssl, SSL_OP_NO_RENEGOTIATION);
+ break;
+ }
+#else
+ sslconn->reneg_state = state;
+#endif
+}

View File

@ -1,83 +0,0 @@
https://issues.redhat.com/browse/RHEL-36755
--- httpd-2.4.59/modules/ssl/ssl_engine_init.c.pkcs11
+++ httpd-2.4.59/modules/ssl/ssl_engine_init.c
@@ -1439,7 +1439,7 @@
if (modssl_is_engine_id(keyfile)) {
apr_status_t rv;
- if ((rv = modssl_load_engine_keypair(s, ptemp, vhost_id,
+ if ((rv = modssl_load_engine_keypair(s, p, ptemp, vhost_id,
engine_certfile, keyfile,
&cert, &pkey))) {
return rv;
--- httpd-2.4.59/modules/ssl/ssl_engine_pphrase.c.pkcs11
+++ httpd-2.4.59/modules/ssl/ssl_engine_pphrase.c
@@ -826,8 +826,19 @@
}
#endif
+#if MODSSL_HAVE_ENGINE_API
+static apr_status_t modssl_engine_cleanup(void *engine)
+{
+ ENGINE *e = engine;
+
+ ENGINE_finish(e);
+
+ return APR_SUCCESS;
+}
+#endif
-apr_status_t modssl_load_engine_keypair(server_rec *s, apr_pool_t *p,
+apr_status_t modssl_load_engine_keypair(server_rec *s,
+ apr_pool_t *pconf, apr_pool_t *ptemp,
const char *vhostid,
const char *certid, const char *keyid,
X509 **pubkey, EVP_PKEY **privkey)
@@ -835,12 +846,12 @@
#if MODSSL_HAVE_ENGINE_API
const char *c, *scheme;
ENGINE *e;
- UI_METHOD *ui_method = get_passphrase_ui(p);
+ UI_METHOD *ui_method = get_passphrase_ui(ptemp);
pphrase_cb_arg_t ppcb;
memset(&ppcb, 0, sizeof ppcb);
ppcb.s = s;
- ppcb.p = p;
+ ppcb.p = ptemp;
ppcb.bPassPhraseDialogOnce = TRUE;
ppcb.key_id = vhostid;
ppcb.pkey_file = keyid;
@@ -853,7 +864,7 @@
return ssl_die(s);
}
- scheme = apr_pstrmemdup(p, keyid, c - keyid);
+ scheme = apr_pstrmemdup(ptemp, keyid, c - keyid);
if (!(e = ENGINE_by_id(scheme))) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10132)
"Init: Failed to load engine for private key %s",
@@ -902,7 +913,8 @@
return ssl_die(s);
}
- ENGINE_finish(e);
+ apr_pool_cleanup_register(pconf, e, modssl_engine_cleanup, modssl_engine_cleanup);
+
ENGINE_free(e);
return APR_SUCCESS;
--- httpd-2.4.59/modules/ssl/ssl_private.h.pkcs11
+++ httpd-2.4.59/modules/ssl/ssl_private.h
@@ -1076,7 +1076,8 @@
/* Load public and/or private key from the configured ENGINE. Private
* key returned as *pkey. certid can be NULL, in which case *pubkey
* is not altered. Errors logged on failure. */
-apr_status_t modssl_load_engine_keypair(server_rec *s, apr_pool_t *p,
+apr_status_t modssl_load_engine_keypair(server_rec *s,
+ apr_pool_t *pconf, apr_pool_t *ptemp,
const char *vhostid,
const char *certid, const char *keyid,
X509 **pubkey, EVP_PKEY **privkey);

View File

@ -1,15 +0,0 @@
Upstream-Status: not pushed upstream
--- httpd-2.4.54/server/log.c.gettid
+++ httpd-2.4.54/server/log.c
@@ -968,7 +972,7 @@
#if APR_HAS_THREADS
field_start = len;
len += cpystrn(buf + len, ":tid ", buflen - len);
- item_len = log_tid(info, NULL, buf + len, buflen - len);
+ item_len = log_tid(info, "g", buf + len, buflen - len);
if (!item_len)
len = field_start;
else

View File

@ -1,55 +0,0 @@
# ./pullrev.sh 1916863
http://svn.apache.org/viewvc?view=revision&revision=1916863
Upstream-Status: in trunk, not proposed for 2.4.x
--- httpd-2.4.59/modules/ssl/ssl_engine_init.c
+++ httpd-2.4.59/modules/ssl/ssl_engine_init.c
@@ -1416,6 +1416,7 @@
const char *vhost_id = mctx->sc->vhost_id, *key_id, *certfile, *keyfile;
int i;
EVP_PKEY *pkey;
+ int custom_dh_done = 0;
#ifdef HAVE_ECC
EC_GROUP *ecgroup = NULL;
int curve_nid = 0;
@@ -1591,14 +1592,14 @@
*/
certfile = APR_ARRAY_IDX(mctx->pks->cert_files, 0, const char *);
if (certfile && !modssl_is_engine_id(certfile)) {
- int done = 0, num_bits = 0;
+ int num_bits = 0;
#if OPENSSL_VERSION_NUMBER < 0x30000000L
DH *dh = modssl_dh_from_file(certfile);
if (dh) {
num_bits = DH_bits(dh);
SSL_CTX_set_tmp_dh(mctx->ssl_ctx, dh);
DH_free(dh);
- done = 1;
+ custom_dh_done = 1;
}
#else
pkey = modssl_dh_pkey_from_file(certfile);
@@ -1608,18 +1609,18 @@
EVP_PKEY_free(pkey);
}
else {
- done = 1;
+ custom_dh_done = 1;
}
}
#endif
- if (done) {
+ if (custom_dh_done) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02540)
"Custom DH parameters (%d bits) for %s loaded from %s",
num_bits, vhost_id, certfile);
}
}
#if !MODSSL_USE_OPENSSL_PRE_1_1_API
- else {
+ if (!custom_dh_done) {
/* If no parameter is manually configured, enable auto
* selection. */
SSL_CTX_set_dh_auto(mctx->ssl_ctx, 1);

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
diff --git a/docs/manual/mod/mpm_common.html.en b/docs/manual/mod/mpm_common.html.en diff --git a/docs/manual/mod/mpm_common.html.en b/docs/manual/mod/mpm_common.html.en
index e7af21d..01d54b7 100644 index d7a2fea..c911a4e 100644
--- a/docs/manual/mod/mpm_common.html.en --- a/docs/manual/mod/mpm_common.html.en
+++ b/docs/manual/mod/mpm_common.html.en +++ b/docs/manual/mod/mpm_common.html.en
@@ -42,6 +42,7 @@ more than one multi-processing module (MPM)</td></tr> @@ -42,6 +42,7 @@ more than one multi-processing module (MPM)</td></tr>
@ -43,10 +43,10 @@ index e7af21d..01d54b7 100644
<div class="directive-section"><h2><a name="ListenBackLog" id="ListenBackLog">ListenBackLog</a> <a name="listenbacklog" id="listenbacklog">Directive</a></h2> <div class="directive-section"><h2><a name="ListenBackLog" id="ListenBackLog">ListenBackLog</a> <a name="listenbacklog" id="listenbacklog">Directive</a></h2>
<table class="directive"> <table class="directive">
diff --git a/include/ap_listen.h b/include/ap_listen.h diff --git a/include/ap_listen.h b/include/ap_listen.h
index 58c2574..1a53292 100644 index d5ed968..be1a60c 100644
--- a/include/ap_listen.h --- a/include/ap_listen.h
+++ b/include/ap_listen.h +++ b/include/ap_listen.h
@@ -137,6 +137,9 @@ AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd, void *dummy @@ -138,6 +138,9 @@ AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd, void *dummy
AP_DECLARE_NONSTD(const char *) ap_set_listencbratio(cmd_parms *cmd, void *dummy, const char *arg); AP_DECLARE_NONSTD(const char *) ap_set_listencbratio(cmd_parms *cmd, void *dummy, const char *arg);
AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
int argc, char *const argv[]); int argc, char *const argv[]);
@ -56,7 +56,7 @@ index 58c2574..1a53292 100644
AP_DECLARE_NONSTD(const char *) ap_set_send_buffer_size(cmd_parms *cmd, void *dummy, AP_DECLARE_NONSTD(const char *) ap_set_send_buffer_size(cmd_parms *cmd, void *dummy,
const char *arg); const char *arg);
AP_DECLARE_NONSTD(const char *) ap_set_receive_buffer_size(cmd_parms *cmd, AP_DECLARE_NONSTD(const char *) ap_set_receive_buffer_size(cmd_parms *cmd,
@@ -150,6 +153,8 @@ AP_INIT_TAKE1("ListenCoresBucketsRatio", ap_set_listencbratio, NULL, RSRC_CONF, @@ -160,6 +163,8 @@ AP_INIT_TAKE1("ListenCoresBucketsRatio", ap_set_listencbratio, NULL, RSRC_CONF,
"Ratio between the number of CPU cores (online) and the number of listeners buckets"), \ "Ratio between the number of CPU cores (online) and the number of listeners buckets"), \
AP_INIT_TAKE_ARGV("Listen", ap_set_listener, NULL, RSRC_CONF, \ AP_INIT_TAKE_ARGV("Listen", ap_set_listener, NULL, RSRC_CONF, \
"A port number or a numeric IP address and a port number, and an optional protocol"), \ "A port number or a numeric IP address and a port number, and an optional protocol"), \
@ -66,10 +66,10 @@ index 58c2574..1a53292 100644
"Send buffer size in bytes"), \ "Send buffer size in bytes"), \
AP_INIT_TAKE1("ReceiveBufferSize", ap_set_receive_buffer_size, NULL, \ AP_INIT_TAKE1("ReceiveBufferSize", ap_set_receive_buffer_size, NULL, \
diff --git a/server/listen.c b/server/listen.c diff --git a/server/listen.c b/server/listen.c
index e2e028a..6ef664b 100644 index 2a4e87a..280bbe7 100644
--- a/server/listen.c --- a/server/listen.c
+++ b/server/listen.c +++ b/server/listen.c
@@ -63,6 +63,7 @@ static int ap_listenbacklog; @@ -60,6 +60,7 @@ static int ap_listenbacklog;
static int ap_listencbratio; static int ap_listencbratio;
static int send_buffer_size; static int send_buffer_size;
static int receive_buffer_size; static int receive_buffer_size;
@ -77,7 +77,7 @@ index e2e028a..6ef664b 100644
#ifdef HAVE_SYSTEMD #ifdef HAVE_SYSTEMD
static int use_systemd = -1; static int use_systemd = -1;
#endif #endif
@@ -162,6 +163,21 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server, int do_bind_ @@ -159,6 +160,21 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server, int do_bind_
} }
#endif #endif
@ -99,7 +99,7 @@ index e2e028a..6ef664b 100644
if (do_bind_listen) { if (do_bind_listen) {
#if APR_HAVE_IPV6 #if APR_HAVE_IPV6
if (server->bind_addr->family == APR_INET6) { if (server->bind_addr->family == APR_INET6) {
@@ -956,6 +972,7 @@ AP_DECLARE(void) ap_listen_pre_config(void) @@ -971,6 +987,7 @@ AP_DECLARE(void) ap_listen_pre_config(void)
} }
} }
@ -107,8 +107,8 @@ index e2e028a..6ef664b 100644
AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
int argc, char *const argv[]) int argc, char *const argv[])
{ {
@@ -1016,6 +1033,14 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, @@ -1044,6 +1061,14 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
return alloc_listener(cmd->server->process, host, port, proto, NULL); scope_id, NULL, cmd->temp_pool);
} }
+AP_DECLARE_NONSTD(const char *) ap_set_freelistener(cmd_parms *cmd, void *dummy, +AP_DECLARE_NONSTD(const char *) ap_set_freelistener(cmd_parms *cmd, void *dummy,

242
httpd-2.4.62-r1919325.patch Normal file
View File

@ -0,0 +1,242 @@
From a0a68b99d131741c1867cff321424892838fc4b3 Mon Sep 17 00:00:00 2001
From: Yann Ylavic <ylavic@apache.org>
Date: Sat, 27 Jul 2024 13:35:53 +0000
Subject: [PATCH] mod_rewrite: Better question mark tracking to avoid
UnsafeAllow3F. PR 69197.
Track in do_expand() whether a '?' in the uri-path comes from a literal in
the substitution string or from an expansion (variable, lookup, ...).
In the former case it's safe to assume that it's the query-string separator
but for the other case it's not (could be a decoded %3f from r->uri).
This allows to avoid [UnsafeAllow3F] for most cases.
Merges r1919325 from trunk
Reviewed by: ylavic, covener, jorton
Github: closes #462
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919545 13f79535-47bb-0310-9956-ffa450edef68
---
modules/mappers/mod_rewrite.c | 107 ++++++++++++++++++++++++++++------
1 file changed, 89 insertions(+), 18 deletions(-)
diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c
index f1c22e3235b..53fb1e91ffb 100644
--- a/modules/mappers/mod_rewrite.c
+++ b/modules/mappers/mod_rewrite.c
@@ -2376,9 +2376,16 @@ static APR_INLINE char *find_char_in_curlies(char *s, int c)
* of an earlier expansion to include expansion specifiers that
* are interpreted by a later expansion, producing results that
* were not intended by the administrator.
+ *
+ * unsafe_qmark if not NULL will be set to 1 or 0 if a question mark
+ * is found respectively in a literal or in a lookup/expansion (whether
+ * it's the first or last qmark depends on [QSL]). Should be initialized
+ * to -1 and remains so if no qmark is found.
*/
-static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
+static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry,
+ int *unsafe_qmark)
{
+#define EXPAND_SPECIALS "\\$%"
result_list *result, *current;
result_list sresult[SMALL_EXPANSION];
unsigned spc = 0;
@@ -2386,8 +2393,29 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
char *p, *c;
apr_pool_t *pool = ctx->r->pool;
- span = strcspn(input, "\\$%");
inputlen = strlen(input);
+ if (!unsafe_qmark) {
+ span = strcspn(input, EXPAND_SPECIALS);
+ }
+ else {
+ span = strcspn(input, EXPAND_SPECIALS "?");
+ if (input[span] == '?') {
+ /* this qmark is not from an expansion thus safe */
+ *unsafe_qmark = 0;
+
+ /* keep tracking only if interested in the last qmark */
+ if (entry && (entry->flags & RULEFLAG_QSLAST)) {
+ do {
+ span++;
+ span += strcspn(input + span, EXPAND_SPECIALS "?");
+ } while (input[span] == '?');
+ }
+ else {
+ unsafe_qmark = NULL;
+ span += strcspn(input + span, EXPAND_SPECIALS);
+ }
+ }
+ }
/* fast exit */
if (inputlen == span) {
@@ -2405,6 +2433,8 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
/* loop for specials */
do {
+ int expanded = 0;
+
/* prepare next entry */
if (current->len) {
current->next = (spc < SMALL_EXPANSION)
@@ -2450,6 +2480,8 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
current->len = span;
current->string = p;
outlen += span;
+
+ expanded = 1;
p = endp + 1;
}
@@ -2489,19 +2521,18 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
}
/* reuse of key variable as result */
- key = lookup_map(ctx->r, map, do_expand(key, ctx, entry));
-
+ key = lookup_map(ctx->r, map, do_expand(key, ctx, entry, NULL));
if (!key && dflt && *dflt) {
- key = do_expand(dflt, ctx, entry);
+ key = do_expand(dflt, ctx, entry, NULL);
}
-
- if (key) {
+ if (key && *key) {
span = strlen(key);
current->len = span;
current->string = key;
outlen += span;
}
+ expanded = 1;
p = endp + 1;
}
}
@@ -2531,8 +2562,9 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
current->len = span;
current->string = bri->source + bri->regmatch[n].rm_so;
}
-
outlen += span;
+
+ expanded = 1;
}
p += 2;
@@ -2545,8 +2577,41 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
++outlen;
}
+ if (unsafe_qmark && expanded && current->len
+ && memchr(current->string, '?', current->len)) {
+ /* this qmark is from an expansion thus unsafe */
+ *unsafe_qmark = 1;
+
+ /* keep tracking only if interested in the last qmark */
+ if (!entry || !(entry->flags & RULEFLAG_QSLAST)) {
+ unsafe_qmark = NULL;
+ }
+ }
+
/* check the remainder */
- if (*p && (span = strcspn(p, "\\$%")) > 0) {
+ if (!unsafe_qmark) {
+ span = strcspn(p, EXPAND_SPECIALS);
+ }
+ else {
+ span = strcspn(p, EXPAND_SPECIALS "?");
+ if (p[span] == '?') {
+ /* this qmark is not from an expansion thus safe */
+ *unsafe_qmark = 0;
+
+ /* keep tracking only if interested in the last qmark */
+ if (entry && (entry->flags & RULEFLAG_QSLAST)) {
+ do {
+ span++;
+ span += strcspn(p + span, EXPAND_SPECIALS "?");
+ } while (p[span] == '?');
+ }
+ else {
+ unsafe_qmark = NULL;
+ span += strcspn(p + span, EXPAND_SPECIALS);
+ }
+ }
+ }
+ if (span > 0) {
if (current->len) {
current->next = (spc < SMALL_EXPANSION)
? &(sresult[spc++])
@@ -2591,7 +2656,7 @@ static void do_expand_env(data_item *env, rewrite_ctx *ctx)
char *name, *val;
while (env) {
- name = do_expand(env->data, ctx, NULL);
+ name = do_expand(env->data, ctx, NULL, NULL);
if (*name == '!') {
name++;
apr_table_unset(ctx->r->subprocess_env, name);
@@ -2725,7 +2790,7 @@ static void add_cookie(request_rec *r, char *s)
static void do_expand_cookie(data_item *cookie, rewrite_ctx *ctx)
{
while (cookie) {
- add_cookie(ctx->r, do_expand(cookie->data, ctx, NULL));
+ add_cookie(ctx->r, do_expand(cookie->data, ctx, NULL, NULL));
cookie = cookie->next;
}
@@ -4014,7 +4079,7 @@ static int apply_rewrite_cond(rewritecond_entry *p, rewrite_ctx *ctx)
int basis;
if (p->ptype != CONDPAT_AP_EXPR)
- input = do_expand(p->input, ctx, NULL);
+ input = do_expand(p->input, ctx, NULL, NULL);
switch (p->ptype) {
case CONDPAT_FILE_EXISTS:
@@ -4178,7 +4243,7 @@ static APR_INLINE void force_type_handler(rewriterule_entry *p,
char *expanded;
if (p->forced_mimetype) {
- expanded = do_expand(p->forced_mimetype, ctx, p);
+ expanded = do_expand(p->forced_mimetype, ctx, p, NULL);
if (*expanded) {
ap_str_tolower(expanded);
@@ -4192,7 +4257,7 @@ static APR_INLINE void force_type_handler(rewriterule_entry *p,
}
if (p->forced_handler) {
- expanded = do_expand(p->forced_handler, ctx, p);
+ expanded = do_expand(p->forced_handler, ctx, p, NULL);
if (*expanded) {
ap_str_tolower(expanded);
@@ -4329,12 +4394,18 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p,
/* expand the result */
if (!(p->flags & RULEFLAG_NOSUB)) {
- newuri = do_expand(p->output, ctx, p);
+ int unsafe_qmark = -1;
+
+ if (p->flags & RULEFLAG_UNSAFE_ALLOW3F) {
+ newuri = do_expand(p->output, ctx, p, NULL);
+ }
+ else {
+ newuri = do_expand(p->output, ctx, p, &unsafe_qmark);
+ }
rewritelog((r, 2, ctx->perdir, "rewrite '%s' -> '%s'", ctx->uri,
newuri));
- if (!(p->flags & RULEFLAG_UNSAFE_ALLOW3F) &&
- ap_strcasestr(r->unparsed_uri, "%3f") &&
- ap_strchr_c(newuri, '?')) {
+
+ if (unsafe_qmark > 0) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10508)
"Unsafe URL with %%3f URL rewritten without "
"UnsafeAllow3F");

View File

@ -1,8 +1,8 @@
diff --git a/server/listen.c b/server/listen.c diff --git a/server/listen.c b/server/listen.c
index 5242c2a..e2e028a 100644 index 9577d60..d718db1 100644
--- a/server/listen.c --- a/server/listen.c
+++ b/server/listen.c +++ b/server/listen.c
@@ -34,6 +34,10 @@ @@ -35,6 +35,10 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
@ -13,7 +13,7 @@ index 5242c2a..e2e028a 100644
/* we know core's module_index is 0 */ /* we know core's module_index is 0 */
#undef APLOG_MODULE_INDEX #undef APLOG_MODULE_INDEX
#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
@@ -59,9 +63,12 @@ static int ap_listenbacklog; @@ -60,9 +64,12 @@ static int ap_listenbacklog;
static int ap_listencbratio; static int ap_listencbratio;
static int send_buffer_size; static int send_buffer_size;
static int receive_buffer_size; static int receive_buffer_size;
@ -27,7 +27,7 @@ index 5242c2a..e2e028a 100644
{ {
apr_socket_t *s = server->sd; apr_socket_t *s = server->sd;
int one = 1; int one = 1;
@@ -94,20 +101,6 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server) @@ -95,20 +102,6 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server)
return stat; return stat;
} }
@ -48,7 +48,7 @@ index 5242c2a..e2e028a 100644
/* /*
* To send data over high bandwidth-delay connections at full * To send data over high bandwidth-delay connections at full
* speed we must force the TCP window to open wide enough to keep the * speed we must force the TCP window to open wide enough to keep the
@@ -169,21 +162,37 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server) @@ -170,21 +163,37 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server)
} }
#endif #endif
@ -100,7 +100,7 @@ index 5242c2a..e2e028a 100644
} }
#ifdef WIN32 #ifdef WIN32
@@ -315,6 +324,123 @@ static int find_listeners(ap_listen_rec **from, ap_listen_rec **to, @@ -335,6 +344,123 @@ static int find_listeners(ap_listen_rec **from, ap_listen_rec **to,
return found; return found;
} }
@ -223,8 +223,8 @@ index 5242c2a..e2e028a 100644
+ +
static const char *alloc_listener(process_rec *process, const char *addr, static const char *alloc_listener(process_rec *process, const char *addr,
apr_port_t port, const char* proto, apr_port_t port, const char* proto,
void *slave) const char *scope_id, void *slave,
@@ -495,7 +621,7 @@ static int open_listeners(apr_pool_t *pool) @@ -529,7 +655,7 @@ static int open_listeners(apr_pool_t *pool)
} }
} }
#endif #endif
@ -233,7 +233,7 @@ index 5242c2a..e2e028a 100644
++num_open; ++num_open;
} }
else { else {
@@ -607,8 +733,28 @@ AP_DECLARE(int) ap_setup_listeners(server_rec *s) @@ -641,8 +767,28 @@ AP_DECLARE(int) ap_setup_listeners(server_rec *s)
} }
} }
@ -264,7 +264,7 @@ index 5242c2a..e2e028a 100644
} }
for (lr = ap_listeners; lr; lr = lr->next) { for (lr = ap_listeners; lr; lr = lr->next) {
@@ -698,7 +844,7 @@ AP_DECLARE(apr_status_t) ap_duplicate_listeners(apr_pool_t *p, server_rec *s, @@ -732,7 +878,7 @@ AP_DECLARE(apr_status_t) ap_duplicate_listeners(apr_pool_t *p, server_rec *s,
duplr->bind_addr); duplr->bind_addr);
return stat; return stat;
} }
@ -273,7 +273,7 @@ index 5242c2a..e2e028a 100644
#if AP_NONBLOCK_WHEN_MULTI_LISTEN #if AP_NONBLOCK_WHEN_MULTI_LISTEN
use_nonblock = (ap_listeners && ap_listeners->next); use_nonblock = (ap_listeners && ap_listeners->next);
stat = apr_socket_opt_set(duplr->sd, APR_SO_NONBLOCK, use_nonblock); stat = apr_socket_opt_set(duplr->sd, APR_SO_NONBLOCK, use_nonblock);
@@ -825,6 +971,11 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, @@ -859,6 +1005,11 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
if (argc < 1 || argc > 2) { if (argc < 1 || argc > 2) {
return "Listen requires 1 or 2 arguments."; return "Listen requires 1 or 2 arguments.";
} }
@ -285,7 +285,7 @@ index 5242c2a..e2e028a 100644
rv = apr_parse_addr_port(&host, &scope_id, &port, argv[0], cmd->pool); rv = apr_parse_addr_port(&host, &scope_id, &port, argv[0], cmd->pool);
if (rv != APR_SUCCESS) { if (rv != APR_SUCCESS) {
@@ -856,6 +1007,12 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, @@ -894,6 +1045,12 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
ap_str_tolower(proto); ap_str_tolower(proto);
} }
@ -295,6 +295,6 @@ index 5242c2a..e2e028a 100644
+ } + }
+#endif +#endif
+ +
return alloc_listener(cmd->server->process, host, port, proto, NULL); return alloc_listener(cmd->server->process, host, port, proto,
scope_id, NULL, cmd->temp_pool);
} }

View File

@ -12,8 +12,8 @@
Summary: Apache HTTP Server Summary: Apache HTTP Server
Name: httpd Name: httpd
Version: 2.4.59 Version: 2.4.62
Release: 7%{?dist} Release: 1%{?dist}
URL: https://httpd.apache.org/ URL: https://httpd.apache.org/
Source0: https://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2 Source0: https://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2
Source1: https://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2.asc Source1: https://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2.asc
@ -77,29 +77,25 @@ Patch24: httpd-2.4.43-corelimit.patch
Patch25: httpd-2.4.57-selinux.patch Patch25: httpd-2.4.57-selinux.patch
Patch26: httpd-2.4.53-icons.patch Patch26: httpd-2.4.53-icons.patch
Patch27: httpd-2.4.43-cachehardmax.patch Patch27: httpd-2.4.43-cachehardmax.patch
Patch28: httpd-2.4.43-socket-activation.patch Patch28: httpd-2.4.62-socket-activation.patch
Patch29: httpd-2.4.43-sslciphdefault.patch Patch29: httpd-2.4.43-sslciphdefault.patch
Patch30: httpd-2.4.43-sslprotdefault.patch Patch30: httpd-2.4.43-sslprotdefault.patch
Patch31: httpd-2.4.43-logjournal.patch Patch31: httpd-2.4.43-logjournal.patch
Patch32: httpd-2.4.48-proxy-ws-idle-timeout.patch Patch32: httpd-2.4.48-proxy-ws-idle-timeout.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=1949606 # https://bugzilla.redhat.com/show_bug.cgi?id=1949606
Patch33: httpd-2.4.46-freebind.patch Patch33: httpd-2.4.62-freebind.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=2065677 # https://bugzilla.redhat.com/show_bug.cgi?id=2065677
Patch34: httpd-2.4.53-separate-systemd-fns.patch Patch34: httpd-2.4.53-separate-systemd-fns.patch
# https://issues.redhat.com/browse/RHEL-5071 # https://issues.redhat.com/browse/RHEL-5071
Patch35: httpd-2.4.57-r1912477+.patch Patch35: httpd-2.4.57-r1912477+.patch
# https://issues.redhat.com/browse/RHEL-35870
Patch36: httpd-2.4.59-unifycgid.patch
Patch37: httpd-2.4.59-gettid.patch
# Bug fixes # Bug fixes
# https://bugzilla.redhat.com/show_bug.cgi?id=1397243 # https://bugzilla.redhat.com/show_bug.cgi?id=1397243
Patch100: httpd-2.4.43-enable-sslv3.patch Patch100: httpd-2.4.43-enable-sslv3.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=1932442 # https://bugzilla.redhat.com/show_bug.cgi?id=1932442
Patch101: httpd-2.4.48-full-release.patch Patch101: httpd-2.4.48-full-release.patch
Patch102: httpd-2.4.59-r1916863.patch # https://bz.apache.org/bugzilla/show_bug.cgi?id=69197
Patch103: httpd-2.4.59-engine-finish.patch Patch102: httpd-2.4.62-r1919325.patch
Patch104: httpd-2.4.51-r1877397.patch
# Security fixes # Security fixes
# https://bugzilla.redhat.com/show_bug.cgi?id=... # https://bugzilla.redhat.com/show_bug.cgi?id=...
@ -258,14 +254,10 @@ written in the Lua programming language.
%patch33 -p1 -b .freebind %patch33 -p1 -b .freebind
%patch34 -p1 -b .separatesystemd %patch34 -p1 -b .separatesystemd
%patch35 -p1 -b .r1912477+ %patch35 -p1 -b .r1912477+
%patch36 -p1 -b .unifycgid
%patch37 -p1 -b .gettid
%patch100 -p1 -b .enable-sslv3 %patch100 -p1 -b .enable-sslv3
%patch101 -p1 -b .full-release %patch101 -p1 -b .full-release
%patch102 -p1 -b .r1916863 %patch102 -p1 -b .r1919325
%patch103 -p1 -b .engine-cleanup
%patch104 -p1 -b .r1877397
# Patch in the vendor string # Patch in the vendor string
sed -i '/^#define PLATFORM/s/Unix/%{vstring}/' os/unix/os.h sed -i '/^#define PLATFORM/s/Unix/%{vstring}/' os/unix/os.h
@ -827,6 +819,10 @@ exit $rv
%{_rpmconfigdir}/macros.d/macros.httpd %{_rpmconfigdir}/macros.d/macros.httpd
%changelog %changelog
* Sat Aug 03 2024 Luboš Uhliarik <luhliari@redhat.com> - 2.4.62-1
- new version 2.4.62
- Resolves: RHEL-52724 - Regression introduced by CVE-2024-38474 fix
* Fri Jul 19 2024 Luboš Uhliarik <luhliari@redhat.com> - 2.4.59-7 * Fri Jul 19 2024 Luboš Uhliarik <luhliari@redhat.com> - 2.4.59-7
- Resolves: RHEL-49856: htcacheclean.service missing [Install] section - Resolves: RHEL-49856: htcacheclean.service missing [Install] section

View File

@ -1,3 +1,3 @@
SHA512 (httpd-2.4.59.tar.bz2) = 209da0bbac5e2564d4590302515b35495be6402273ff4024aa93e85e44554c95e053201d606383936425a41e1b5b97e6b40055dcbb385eb691a5029a6f3158c2 SHA512 (httpd-2.4.62.tar.bz2) = 7db1876805d5c0f60f49bcb51f75cdf567120f2ff6349e68f084e9a86ae38265d9f1c67e7fca0082c9db136f3c408a88501ee11f26b1b68724ba240867171d77
SHA512 (httpd-2.4.59.tar.bz2.asc) = 85237e204e57d930e2b7a85a21f8d593e81895f96350c3a345978538a536f3c0614ba89256905c0aa558880fc6fb10608b8dd7cbd026af326b1d83601c267f2d SHA512 (httpd-2.4.62.tar.bz2.asc) = ed4d59fca7e134aa378dddfd0d62973da99fe77a82a48e268e11262af8aca4a4e90133cc979fb39a4f9cb33abbebb10b1345cb52cfad6eb58fc84d3308bc5a39
SHA512 (KEYS) = 88c848b7ab9e4915d6625dcad3e8328673b0448f2ce76f2c44eecc612cf6afbce3287a4ee7219a44c6fcc61d5ecb2a1a8545456a4a16b90400263d7249cbf192 SHA512 (KEYS) = 88c848b7ab9e4915d6625dcad3e8328673b0448f2ce76f2c44eecc612cf6afbce3287a4ee7219a44c6fcc61d5ecb2a1a8545456a4a16b90400263d7249cbf192