commit 8e657e835965c3a011375feaa0359921c5b3e2dd (refs/remotes/origin/v3.5)
Author: Amos Jeffries <yadij@users.noreply.github.com>
Date:   2019-08-13 13:50:06 +0000

    Ignore malformed Host header in intercept and reverse proxy mode (#456)

From 21d99bdeaed7b2208098d824496da954920ea720 Mon Sep 17 00:00:00 2001
From: Armin Wolfermann <aw@osn.de>
Date: Tue, 4 Feb 2020 21:15:00 +0100
Subject: [PATCH] fix security patch

Index: squid-3.1.23/src/client_side.cc
===================================================================
--- squid-3.1.23.orig/src/client_side.cc
+++ squid-3.1.23/src/client_side.cc
@@ -105,6 +105,7 @@
 #include "SquidTime.h"
 #include "ChunkedCodingParser.h"
 #include "rfc1738.h"
+#include "base/CharacterSet.h"
 
 #if USE_SSL
 #include "ssl/context_storage.h"
@@ -1845,6 +1846,23 @@ setLogUri(ClientHttpRequest * http, char
     }
 }
 
+static char *
+getHostHeader(const char *req_hdr)
+{
+    char *host = mime_get_header(req_hdr, "Host");
+    if (!host)
+        return NULL;
+
+    // check the header contents are valid
+    for(const char *c = host; *c != '\0'; ++c) {
+        // currently only used for pre-parse Host header, ensure valid domain[:port] or ip[:port]
+        static const CharacterSet hostChars = CharacterSet("host",":[].-_") + CharacterSet::ALPHA + CharacterSet::DIGIT;
+        if (!hostChars[*c])
+            return NULL; // error. line contains character not accepted in Host header
+    }
+    return host;
+}
+
 static void
 prepareAcceleratedURL(ConnStateData * conn, ClientHttpRequest *http, char *url, const char *req_hdr)
 {
@@ -1892,9 +1910,9 @@ prepareAcceleratedURL(ConnStateData * co
 
     const bool switchedToHttps = conn->switchedToHttps();
     const bool tryHostHeader = vhost || switchedToHttps;
-    if (tryHostHeader && (host = mime_get_header(req_hdr, "Host")) != NULL) {
+    if (tryHostHeader && (host = getHostHeader(req_hdr)) != NULL && strlen(host) <= SQUIDHOSTNAMELEN) {
         debugs(33, 5, "ACCEL VHOST REWRITE: vhost=" << host << " + vport=" << vport);
-        char thost[256];
+        char thost[SQUIDHOSTNAMELEN + 6 /* ':' vport */];
         if (vport > 0) {
             thost[0] = '\0';
             char *t = NULL;
@@ -1951,7 +1969,7 @@ prepareTransparentURL(ConnStateData * co
 
     /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
 
-    if ((host = mime_get_header(req_hdr, "Host")) != NULL) {
+    if ((host = getHostHeader(req_hdr)) != NULL) {
         int url_sz = strlen(url) + 32 + Config.appendDomainLen +
                      strlen(host);
         http->uri = (char *)xcalloc(url_sz, 1);
Index: squid-3.1.23/src/base/CharacterSet.cc
===================================================================
--- /dev/null
+++ squid-3.1.23/src/base/CharacterSet.cc
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#include "squid.h"
+#include "base/CharacterSet.h"
+
+#include <algorithm>
+#include <functional>
+
+CharacterSet &
+CharacterSet::operator +=(const CharacterSet &src)
+{
+    Storage::const_iterator s = src.chars_.begin();
+    const Storage::const_iterator e = src.chars_.end();
+    Storage::iterator d = chars_.begin();
+    while (s != e) {
+        if (*s)
+            *d = 1;
+        ++s;
+        ++d;
+    }
+    return *this;
+}
+
+CharacterSet
+CharacterSet::operator +(const CharacterSet &src) const
+{
+    CharacterSet rv(*this);
+    rv += src;
+    return rv;
+}
+
+CharacterSet &
+CharacterSet::add(const unsigned char c)
+{
+    chars_[static_cast<uint8_t>(c)] = 1;
+    return *this;
+}
+
+CharacterSet &
+CharacterSet::addRange(unsigned char low, unsigned char high)
+{
+    //manual loop splitting is needed to cover case where high is 255
+    // otherwise low will wrap, resulting in infinite loop
+    while (low < high) {
+        chars_[static_cast<uint8_t>(low)] = 1;
+        ++low;
+    }
+    chars_[static_cast<uint8_t>(high)] = 1;
+    return *this;
+}
+
+CharacterSet
+CharacterSet::complement(const char *label) const
+{
+    CharacterSet result((label ? label : "complement_of_some_other_set"), "");
+    // negate each of our elements and add them to the result storage
+    std::transform(chars_.begin(), chars_.end(), result.chars_.begin(),
+                   std::logical_not<Storage::value_type>());
+    return result;
+}
+
+CharacterSet::CharacterSet(const char *label, const char * const c) :
+    name(label == NULL ? "anonymous" : label),
+    chars_(Storage(256,0))
+{
+    const size_t clen = strlen(c);
+    for (size_t i = 0; i < clen; ++i)
+        add(c[i]);
+}
+
+CharacterSet::CharacterSet(const char *label, unsigned char low, unsigned char high) :
+    name(label == NULL ? "anonymous" : label),
+    chars_(Storage(256,0))
+{
+    addRange(low,high);
+}
+
+const CharacterSet
+// RFC 5234
+CharacterSet::ALPHA("ALPHA", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"),
+             CharacterSet::BIT("BIT","01"),
+             CharacterSet::CR("CR","\r"),
+#if __cplusplus == 201103L
+//CharacterSet::CTL("CTL",{{0x01,0x1f},{0x7f,0x7f}}),
+#endif
+             CharacterSet::DIGIT("DIGIT","0123456789"),
+             CharacterSet::DQUOTE("DQUOTE","\""),
+             CharacterSet::HEXDIG("HEXDIG","0123456789aAbBcCdDeEfF"),
+             CharacterSet::HTAB("HTAB","\t"),
+             CharacterSet::LF("LF","\n"),
+             CharacterSet::SP("SP"," "),
+             CharacterSet::VCHAR("VCHAR", 0x21, 0x7e),
+// RFC 7230
+             CharacterSet::WSP("WSP"," \t"),
+#if __cplusplus == 201103L
+//CharacterSet::CTEXT("ctext",{{0x09,0x09},{0x20,0x20},{0x2a,0x5b},{0x5d,0x7e},{0x80,0xff}}),
+#endif
+             CharacterSet::TCHAR("TCHAR","!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"),
+             CharacterSet::SPECIAL("SPECIAL","()<>@,;:\\\"/[]?={}"),
+#if __cplusplus == 201103L
+//CharacterSet::QDTEXT("QDTEXT",{{0x09,0x09},{0x20,0x21},{0x23,0x5b},{0x5d,0x7e},{0x80,0xff}}),
+#endif
+             CharacterSet::OBSTEXT("OBSTEXT",0x80,0xff),
+// RFC 7232
+#if __cplusplus == 201103L
+//CharacterSet::ETAGC("ETAGC",{{0x21,0x21},{0x23,0x7e},{0x80,0xff}}),
+#endif
+// RFC 7235
+             CharacterSet::TOKEN68C("TOKEN68C","-._~+/0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
+             ;
+
Index: squid-3.1.23/src/Makefile.am
===================================================================
--- squid-3.1.23.orig/src/Makefile.am
+++ squid-3.1.23/src/Makefile.am
@@ -21,6 +21,7 @@ DNSSOURCE += \
 
 SBUF_SOURCE= \
 	base/CharacterSet.h \
+    base/CharacterSet.cc \
 	base/InstanceId.h \
 	MemBlob.h \
 	MemBlob.cc \
