From 71264795f3a39cf0485c3e875bfa34cd25ebc4a1 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: May 06 2020 12:25:41 +0000 Subject: import squid-3.5.20-15.el7_8.1 --- diff --git a/SOURCES/squid-3.5.20-CVE-2019-12519.patch b/SOURCES/squid-3.5.20-CVE-2019-12519.patch new file mode 100644 index 0000000..568b277 --- /dev/null +++ b/SOURCES/squid-3.5.20-CVE-2019-12519.patch @@ -0,0 +1,275 @@ +diff --git a/src/esi/Context.h b/src/esi/Context.h +index be49742..34b1fd0 100644 +--- a/src/esi/Context.h ++++ b/src/esi/Context.h +@@ -12,6 +12,7 @@ + #include "clientStream.h" + #include "err_type.h" + #include "esi/Element.h" ++#include "esi/Esi.h" + #include "esi/Parser.h" + #include "http/StatusCode.h" + #include "HttpReply.h" +@@ -112,7 +113,7 @@ public: + { + + public: +- ESIElement::Pointer stack[10]; /* a stack of esi elements that are open */ ++ ESIElement::Pointer stack[ESI_STACK_DEPTH_LIMIT]; /* a stack of esi elements that are open */ + int stackdepth; /* self explanatory */ + ESIParser::Pointer theParser; + ESIElement::Pointer top(); +diff --git a/src/esi/Esi.cc b/src/esi/Esi.cc +index 1816c76..674bae2 100644 +--- a/src/esi/Esi.cc ++++ b/src/esi/Esi.cc +@@ -29,6 +29,7 @@ + #include "esi/Expression.h" + #include "esi/Segment.h" + #include "esi/VarState.h" ++#include "FadingCounter.h" + #include "HttpHdrSc.h" + #include "HttpHdrScTarget.h" + #include "HttpReply.h" +@@ -943,13 +944,18 @@ void + ESIContext::addStackElement (ESIElement::Pointer element) + { + /* Put on the stack to allow skipping of 'invalid' markup */ +- assert (parserState.stackdepth <11); ++ ++ // throw an error if the stack location would be invalid ++ if (parserState.stackdepth >= ESI_STACK_DEPTH_LIMIT) ++ throw Esi::Error("ESI Too many nested elements"); ++ if (parserState.stackdepth < 0) ++ throw Esi::Error("ESI elements stack error, probable error in ESI template"); ++ + assert (!failed()); + debugs(86, 5, "ESIContext::addStackElement: About to add ESI Node " << element.getRaw()); + + if (!parserState.top()->addElement(element)) { +- debugs(86, DBG_IMPORTANT, "ESIContext::addStackElement: failed to add esi node, probable error in ESI template"); +- flags.error = 1; ++ throw Esi::Error("ESIContext::addStackElement failed, probable error in ESI template"); + } else { + /* added ok, push onto the stack */ + parserState.stack[parserState.stackdepth] = element; +@@ -1201,13 +1207,10 @@ ESIContext::addLiteral (const char *s, int len) + assert (len); + debugs(86, 5, "literal length is " << len); + /* give a literal to the current element */ +- assert (parserState.stackdepth <11); + ESIElement::Pointer element (new esiLiteral (this, s, len)); + +- if (!parserState.top()->addElement(element)) { +- debugs(86, DBG_IMPORTANT, "ESIContext::addLiteral: failed to add esi node, probable error in ESI template"); +- flags.error = 1; +- } ++ if (!parserState.top()->addElement(element)) ++ throw Esi::Error("ESIContext::addLiteral failed, probable error in ESI template"); + } + + void +@@ -1269,8 +1272,24 @@ ESIContext::parse() + + PROF_start(esiParsing); + +- while (buffered.getRaw() && !flags.error) +- parseOneBuffer(); ++ try { ++ while (buffered.getRaw() && !flags.error) ++ parseOneBuffer(); ++ ++ } catch (Esi::ErrorDetail &errMsg) { // FIXME: non-const for c_str() ++ // level-2: these are protocol/syntax errors from upstream ++ debugs(86, 2, "WARNING: ESI syntax error: " << errMsg); ++ setError(); ++ setErrorMessage(errMsg.c_str()); ++ ++ } catch (...) { ++ // DBG_IMPORTANT because these are local issues the admin needs to fix ++ static FadingCounter logEntries; // TODO: set horizon less than infinity ++ if (logEntries.count(1) < 100) ++ debugs(86, DBG_IMPORTANT, "ERROR: ESI parser: unhandled exception"); ++ setError(); ++ setErrorMessage("ESI parser error"); ++ } + + PROF_stop(esiParsing); + +diff --git a/src/esi/Esi.h b/src/esi/Esi.h +index bbdb566..85f80f7 100644 +--- a/src/esi/Esi.h ++++ b/src/esi/Esi.h +@@ -10,6 +10,11 @@ + #define SQUID_ESI_H + + #include "clientStream.h" ++#include "SBuf.h" ++ ++#if !defined(ESI_STACK_DEPTH_LIMIT) ++#define ESI_STACK_DEPTH_LIMIT 20 ++#endif + + /* ESI.c */ + extern CSR esiStreamRead; +@@ -18,5 +23,14 @@ extern CSD esiStreamDetach; + extern CSS esiStreamStatus; + int esiEnableProcessing (HttpReply *); + ++namespace Esi ++{ ++ ++typedef SBuf ErrorDetail; ++/// prepare an Esi::ErrorDetail for throw on ESI parser internal errors ++inline Esi::ErrorDetail Error(const char *msg) { return ErrorDetail(msg); } ++ ++} // namespace Esi ++ + #endif /* SQUID_ESI_H */ + +diff --git a/src/esi/Expression.cc b/src/esi/Expression.cc +index 8a1d3e9..a65edfb 100644 +--- a/src/esi/Expression.cc ++++ b/src/esi/Expression.cc +@@ -10,6 +10,7 @@ + + #include "squid.h" + #include "Debug.h" ++#include "esi/Esi.h" + #include "esi/Expression.h" + #include "profiler/Profiler.h" + +@@ -97,6 +98,17 @@ stackpop(stackmember * s, int *depth) + cleanmember(&s[*depth]); + } + ++static void ++stackpush(stackmember *stack, stackmember &item, int *depth) ++{ ++ if (*depth < 0) ++ throw Esi::Error("ESIExpression stack has negative size"); ++ if (*depth >= ESI_STACK_DEPTH_LIMIT) ++ throw Esi::Error("ESIExpression stack is full, cannot push"); ++ ++ stack[(*depth)++] = item; ++} ++ + static evaluate evalnegate; + static evaluate evalliteral; + static evaluate evalor; +@@ -208,6 +220,11 @@ evalnegate(stackmember * stack, int *depth, int whereAmI, stackmember * candidat + /* invalid stack */ + return 1; + ++ if (whereAmI < 0) ++ throw Esi::Error("negate expression location too small"); ++ if (*depth >= ESI_STACK_DEPTH_LIMIT) ++ throw Esi::Error("negate expression too complex"); ++ + if (stack[whereAmI + 1].valuetype != ESI_EXPR_EXPR) + /* invalid operand */ + return 1; +@@ -280,7 +297,7 @@ evalor(stackmember * stack, int *depth, int whereAmI, stackmember * candidate) + + srv.precedence = 1; + +- stack[(*depth)++] = srv; ++ stackpush(stack, srv, depth); + + /* we're out of way, try adding now */ + if (!addmember(stack, depth, candidate)) +@@ -327,7 +344,7 @@ evaland(stackmember * stack, int *depth, int whereAmI, stackmember * candidate) + + srv.precedence = 1; + +- stack[(*depth)++] = srv; ++ stackpush(stack, srv, depth); + + /* we're out of way, try adding now */ + if (!addmember(stack, depth, candidate)) +@@ -373,7 +390,7 @@ evallesseq(stackmember * stack, int *depth, int whereAmI, stackmember * candidat + + srv.precedence = 1; + +- stack[(*depth)++] = srv; ++ stackpush(stack, srv, depth); + + /* we're out of way, try adding now */ + if (!addmember(stack, depth, candidate)) +@@ -421,7 +438,7 @@ evallessthan(stackmember * stack, int *depth, int whereAmI, stackmember * candid + + srv.precedence = 1; + +- stack[(*depth)++] = srv; ++ stackpush(stack, srv, depth); + + /* we're out of way, try adding now */ + if (!addmember(stack, depth, candidate)) +@@ -469,7 +486,7 @@ evalmoreeq(stackmember * stack, int *depth, int whereAmI, stackmember * candidat + + srv.precedence = 1; + +- stack[(*depth)++] = srv; ++ stackpush(stack, srv, depth); + + /* we're out of way, try adding now */ + if (!addmember(stack, depth, candidate)) +@@ -517,7 +534,7 @@ evalmorethan(stackmember * stack, int *depth, int whereAmI, stackmember * candid + + srv.precedence = 1; + +- stack[(*depth)++] = srv; ++ stackpush(stack, srv, depth); + + /* we're out of way, try adding now */ + if (!addmember(stack, depth, candidate)) +@@ -566,7 +583,7 @@ evalequals(stackmember * stack, int *depth, int whereAmI, + + srv.precedence = 1; + +- stack[(*depth)++] = srv; ++ stackpush(stack, srv, depth); + + /* we're out of way, try adding now */ + if (!addmember(stack, depth, candidate)) +@@ -613,7 +630,7 @@ evalnotequals(stackmember * stack, int *depth, int whereAmI, stackmember * candi + + srv.precedence = 1; + +- stack[(*depth)++] = srv; ++ stackpush(stack, srv, depth); + + /* we're out of way, try adding now */ + if (!addmember(stack, depth, candidate)) +@@ -953,6 +970,9 @@ addmember(stackmember * stack, int *stackdepth, stackmember * candidate) + /* !(!(a==b))) is why thats safe */ + /* strictly less than until we unwind */ + ++ if (*stackdepth >= ESI_STACK_DEPTH_LIMIT) ++ throw Esi::Error("ESI expression too complex to add member"); ++ + if (candidate->precedence < stack[*stackdepth - 1].precedence || + candidate->precedence < stack[*stackdepth - 2].precedence) { + /* must be an operator */ +@@ -968,10 +988,10 @@ addmember(stackmember * stack, int *stackdepth, stackmember * candidate) + return 0; + } + } else { +- stack[(*stackdepth)++] = *candidate; ++ stackpush(stack, *candidate, stackdepth); + } + } else if (candidate->valuetype != ESI_EXPR_INVALID) +- stack[(*stackdepth)++] = *candidate; ++ stackpush(stack, *candidate, stackdepth); + + return 1; + } +@@ -979,7 +999,7 @@ addmember(stackmember * stack, int *stackdepth, stackmember * candidate) + int + ESIExpression::Evaluate(char const *s) + { +- stackmember stack[20]; ++ stackmember stack[ESI_STACK_DEPTH_LIMIT]; + int stackdepth = 0; + char const *end; + PROF_start(esiExpressionEval); diff --git a/SOURCES/squid-3.5.20-CVE-2019-12525.patch b/SOURCES/squid-3.5.20-CVE-2019-12525.patch new file mode 100644 index 0000000..6bfe4e3 --- /dev/null +++ b/SOURCES/squid-3.5.20-CVE-2019-12525.patch @@ -0,0 +1,30 @@ +commit ec0d0f39cf28da14eead0ba5e777e95855bc2f67 +Author: Amos Jeffries +Date: 2019-06-08 21:09:23 +0000 + + Fix Digest auth parameter parsing (#415) + + Only remove quoting if the domain=, uri= or qop= parameter + value is surrounded by double-quotes. + +diff --git a/src/auth/digest/Config.cc b/src/auth/digest/Config.cc +index 674dd93..d2cd2e9 100644 +--- a/src/auth/digest/Config.cc ++++ b/src/auth/digest/Config.cc +@@ -781,14 +781,14 @@ Auth::Digest::Config::decode(char const *proxy_auth, const char *aRequestRealm) + if (keyName == SBuf("domain",6) || keyName == SBuf("uri",3)) { + // domain is Special. Not a quoted-string, must not be de-quoted. But is wrapped in '"' + // BUG 3077: uri= can also be sent to us in a mangled (invalid!) form like domain +- if (*p == '"' && *(p + vlen -1) == '"') { ++ if (vlen > 1 && *p == '"' && *(p + vlen -1) == '"') { + value.limitInit(p+1, vlen-2); + } + } else if (keyName == SBuf("qop",3)) { + // qop is more special. + // On request this must not be quoted-string de-quoted. But is several values wrapped in '"' + // On response this is a single un-quoted token. +- if (*p == '"' && *(p + vlen -1) == '"') { ++ if (vlen > 1 && *p == '"' && *(p + vlen -1) == '"') { + value.limitInit(p+1, vlen-2); + } else { + value.limitInit(p, vlen); diff --git a/SOURCES/squid-3.5.20-CVE-2020-11945.patch b/SOURCES/squid-3.5.20-CVE-2020-11945.patch new file mode 100644 index 0000000..281b5cb --- /dev/null +++ b/SOURCES/squid-3.5.20-CVE-2020-11945.patch @@ -0,0 +1,50 @@ +diff --git a/src/auth/digest/Config.cc b/src/auth/digest/Config.cc +index 4a9e762..1008ca6 100644 +--- a/src/auth/digest/Config.cc ++++ b/src/auth/digest/Config.cc +@@ -85,9 +85,6 @@ static void authenticateDigestNonceDelete(digest_nonce_h * nonce); + static void authenticateDigestNonceSetup(void); + static void authDigestNonceEncode(digest_nonce_h * nonce); + static void authDigestNonceLink(digest_nonce_h * nonce); +-#if NOT_USED +-static int authDigestNonceLinks(digest_nonce_h * nonce); +-#endif + static void authDigestNonceUserUnlink(digest_nonce_h * nonce); + + static void +@@ -276,21 +273,10 @@ authDigestNonceLink(digest_nonce_h * nonce) + { + assert(nonce != NULL); + ++nonce->references; ++ assert(nonce->references != 0); // no overflows + debugs(29, 9, "nonce '" << nonce << "' now at '" << nonce->references << "'."); + } + +-#if NOT_USED +-static int +-authDigestNonceLinks(digest_nonce_h * nonce) +-{ +- if (!nonce) +- return -1; +- +- return nonce->references; +-} +- +-#endif +- + void + authDigestNonceUnlink(digest_nonce_h * nonce) + { +diff --git a/src/auth/digest/Config.h b/src/auth/digest/Config.h +index 8baeb31..c7b353d 100644 +--- a/src/auth/digest/Config.h ++++ b/src/auth/digest/Config.h +@@ -42,7 +42,7 @@ struct _digest_nonce_h : public hash_link { + /* number of uses we've seen of this nonce */ + unsigned long nc; + /* reference count */ +- short references; ++ uint64_t references; + /* the auth_user this nonce has been tied to */ + Auth::Digest::User *user; + /* has this nonce been invalidated ? */ diff --git a/SPECS/squid.spec b/SPECS/squid.spec index 971fa13..1dbe49b 100644 --- a/SPECS/squid.spec +++ b/SPECS/squid.spec @@ -4,7 +4,7 @@ Name: squid Version: 3.5.20 -Release: 15%{?dist} +Release: 15%{?dist}.1 Summary: The Squid proxy caching server Epoch: 7 # See CREDITS for breakdown of non GPLv2+ code @@ -66,6 +66,12 @@ Patch500: squid-3.5.20-CVE-2019-13345.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1582301 Patch501: squid-3.5.20-CVE-2018-1000024.patch Patch502: squid-3.5.20-CVE-2018-1000027.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1828361 +Patch503: squid-3.5.20-CVE-2020-11945.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1828362 +Patch504: squid-3.5.20-CVE-2019-12519.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1829772 +Patch505: squid-3.5.20-CVE-2019-12525.patch Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Requires: bash >= 2.0 @@ -156,6 +162,9 @@ migration and script which prepares squid for downgrade operation. %patch500 -p1 -b .CVE-2019-13345 %patch501 -p1 -b .CVE-2018-1000024 %patch502 -p1 -b .CVE-2018-1000027 +%patch503 -p1 -b .CVE-2020-11945 +%patch504 -p1 -b .CVE-2019-12519 +%patch505 -p1 -b .CVE-2019-12525 # https://bugzilla.redhat.com/show_bug.cgi?id=1471140 # Patch in the vendor documentation and used different location for documentation @@ -385,6 +394,14 @@ fi chgrp squid /var/cache/samba/winbindd_privileged >/dev/null 2>&1 || : %changelog +* Tue Apr 28 2020 Lubos Uhliarik - 7:3.5.20-15.1 +- Resolves: #1828359 - CVE-2020-11945 squid: improper access restriction upon + Digest Authentication nonce replay could lead to remote code execution +- Resolves: #1828360 - CVE-2019-12519 squid: improper check for new member in + ESIExpression::Evaluate allows for stack buffer overflow +- Resolves: #1829772 - CVE-2019-12525 squid: parsing of header + Proxy-Authentication leads to memory corruption + * Thu Jul 25 2019 Lubos Uhliarik - 7:3.5.20-15 - Resolves: #1690551 - Squid cache_peer DNS lookup failed when not all lower case