Version in base suite: 5.7-2 Base version: squid_5.7-2 Target version: squid_5.7-2+deb12u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/s/squid/squid_5.7-2.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/s/squid/squid_5.7-2+deb12u1.dsc changelog | 20 ++ patches/CVE-2023-46724.patch | 34 +++ patches/CVE-2023-46846.patch | 176 ++++++++++++++++++ patches/CVE-2023-46847.patch | 33 +++ patches/CVE-2023-46848.patch | 37 +++ patches/CVE-2023-49285.patch | 27 ++ patches/CVE-2023-49286.patch | 72 +++++++ patches/CVE-2023-50269.patch | 61 ++++++ patches/CVE-2024-23638.patch | 21 ++ patches/CVE-2024-25111.patch | 399 +++++++++++++++++++++++++++++++++++++++++++ patches/CVE-2024-25617.patch | 117 ++++++++++++ patches/series | 10 + 12 files changed, 1007 insertions(+) diff -Nru squid-5.7/debian/changelog squid-5.7/debian/changelog --- squid-5.7/debian/changelog 2023-04-28 06:35:27.000000000 +0000 +++ squid-5.7/debian/changelog 2024-03-05 22:14:44.000000000 +0000 @@ -1,3 +1,23 @@ +squid (5.7-2+deb12u1) bookworm-security; urgency=high + + * Non-maintainer upload. + * Fix CVE-2023-46724, CVE-2023-46846, CVE-2023-46847, CVE-2023-46848, + CVE-2023-49285, CVE-2023-49286, CVE-2023-50269, CVE-2024-23638, + CVE-2024-25111, CVE-2024-25617. + * Several security vulnerabilities have been discovered in Squid, a full + featured web proxy cache. Due to programming errors in Squid's HTTP request + parsing, remote attackers may be able to execute a denial of service attack + by sending large X-Forwarded-For header or trigger a stack buffer overflow + while performing HTTP Digest authentication. Other issues facilitate + request smuggling past a firewall or a denial of service against Squid's + Helper process management. + In regard to CVE-2023-46728: Please note that support for the Gopher + protocol has simply been removed in future Squid versions. There are no + plans by the upstream developers of Squid to fix this issue. We recommend + to reject all Gopher URL requests instead. + + -- Markus Koschany Tue, 05 Mar 2024 23:14:44 +0100 + squid (5.7-2) unstable; urgency=medium * Add a couple of upstream picked patches to fix some issues on 5.7 diff -Nru squid-5.7/debian/patches/CVE-2023-46724.patch squid-5.7/debian/patches/CVE-2023-46724.patch --- squid-5.7/debian/patches/CVE-2023-46724.patch 1970-01-01 00:00:00.000000000 +0000 +++ squid-5.7/debian/patches/CVE-2023-46724.patch 2024-03-05 22:14:44.000000000 +0000 @@ -0,0 +1,34 @@ +From: Markus Koschany +Date: Mon, 19 Feb 2024 12:09:15 +0100 +Subject: CVE-2023-46724 + +Bug-Debian: https://bugs.debian.org/1055252 +Origin: http://www.squid-cache.org/Versions/v5/SQUID-2023_4.patch +--- + src/anyp/Uri.cc | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/anyp/Uri.cc b/src/anyp/Uri.cc +index 94b3bb4..7ccad93 100644 +--- a/src/anyp/Uri.cc ++++ b/src/anyp/Uri.cc +@@ -173,6 +173,10 @@ urlInitialize(void) + assert(0 == matchDomainName("*.foo.com", ".foo.com", mdnHonorWildcards)); + assert(0 != matchDomainName("*.foo.com", "foo.com", mdnHonorWildcards)); + ++ assert(0 != matchDomainName("foo.com", "")); ++ assert(0 != matchDomainName("foo.com", "", mdnHonorWildcards)); ++ assert(0 != matchDomainName("foo.com", "", mdnRejectSubsubDomains)); ++ + /* more cases? */ + } + +@@ -756,6 +760,8 @@ matchDomainName(const char *h, const char *d, MatchDomainNameFlags flags) + return -1; + + dl = strlen(d); ++ if (dl == 0) ++ return 1; + + /* + * Start at the ends of the two strings and work towards the diff -Nru squid-5.7/debian/patches/CVE-2023-46846.patch squid-5.7/debian/patches/CVE-2023-46846.patch --- squid-5.7/debian/patches/CVE-2023-46846.patch 1970-01-01 00:00:00.000000000 +0000 +++ squid-5.7/debian/patches/CVE-2023-46846.patch 2024-03-05 22:14:44.000000000 +0000 @@ -0,0 +1,176 @@ +From: Markus Koschany +Date: Mon, 19 Feb 2024 12:10:02 +0100 +Subject: CVE-2023-46846 + +Bug-Debian: https://bugs.debian.org/1054537 +Origin: http://www.squid-cache.org/Versions/v5/SQUID-2023_1.patch +--- + src/http/one/Parser.cc | 8 +------- + src/http/one/Parser.h | 4 +--- + src/http/one/TeChunkedParser.cc | 23 ++++++++++++++++++----- + src/parser/Tokenizer.cc | 12 ++++++++++++ + src/parser/Tokenizer.h | 7 +++++++ + 5 files changed, 39 insertions(+), 15 deletions(-) + +diff --git a/src/http/one/Parser.cc b/src/http/one/Parser.cc +index 33c9978..df20d33 100644 +--- a/src/http/one/Parser.cc ++++ b/src/http/one/Parser.cc +@@ -65,16 +65,10 @@ Http::One::Parser::DelimiterCharacters() + void + Http::One::Parser::skipLineTerminator(Tokenizer &tok) const + { +- if (tok.skip(Http1::CrLf())) +- return; +- + if (Config.onoff.relaxed_header_parser && tok.skipOne(CharacterSet::LF)) + return; + +- if (tok.atEnd() || (tok.remaining().length() == 1 && tok.remaining().at(0) == '\r')) +- throw InsufficientInput(); +- +- throw TexcHere("garbage instead of CRLF line terminator"); ++ tok.skipRequired("line-terminating CRLF", Http1::CrLf()); + } + + /// all characters except the LF line terminator +diff --git a/src/http/one/Parser.h b/src/http/one/Parser.h +index 7216401..c82248a 100644 +--- a/src/http/one/Parser.h ++++ b/src/http/one/Parser.h +@@ -124,9 +124,7 @@ protected: + * detect and skip the CRLF or (if tolerant) LF line terminator + * consume from the tokenizer. + * +- * \throws exception on bad or InsuffientInput. +- * \retval true only if line terminator found. +- * \retval false incomplete or missing line terminator, need more data. ++ * \throws exception on bad or InsufficientInput + */ + void skipLineTerminator(Tokenizer &) const; + +diff --git a/src/http/one/TeChunkedParser.cc b/src/http/one/TeChunkedParser.cc +index 132d4d0..8500083 100644 +--- a/src/http/one/TeChunkedParser.cc ++++ b/src/http/one/TeChunkedParser.cc +@@ -91,6 +91,11 @@ Http::One::TeChunkedParser::parseChunkSize(Tokenizer &tok) + { + Must(theChunkSize <= 0); // Should(), really + ++ static const SBuf bannedHexPrefixLower("0x"); ++ static const SBuf bannedHexPrefixUpper("0X"); ++ if (tok.skip(bannedHexPrefixLower) || tok.skip(bannedHexPrefixUpper)) ++ throw TextException("chunk starts with 0x", Here()); ++ + int64_t size = -1; + if (tok.int64(size, 16, false) && !tok.atEnd()) { + if (size < 0) +@@ -121,7 +126,7 @@ Http::One::TeChunkedParser::parseChunkMetadataSuffix(Tokenizer &tok) + // bad or insufficient input, like in the code below. TODO: Expand up. + try { + parseChunkExtensions(tok); // a possibly empty chunk-ext list +- skipLineTerminator(tok); ++ tok.skipRequired("CRLF after [chunk-ext]", Http1::CrLf()); + buf_ = tok.remaining(); + parsingStage_ = theChunkSize ? Http1::HTTP_PARSE_CHUNK : Http1::HTTP_PARSE_MIME; + return true; +@@ -132,12 +137,14 @@ Http::One::TeChunkedParser::parseChunkMetadataSuffix(Tokenizer &tok) + // other exceptions bubble up to kill message parsing + } + +-/// Parses the chunk-ext list (RFC 7230 section 4.1.1 and its Errata #4667): ++/// Parses the chunk-ext list (RFC 9112 section 7.1.1: + /// chunk-ext = *( BWS ";" BWS chunk-ext-name [ BWS "=" BWS chunk-ext-val ] ) + void +-Http::One::TeChunkedParser::parseChunkExtensions(Tokenizer &tok) ++Http::One::TeChunkedParser::parseChunkExtensions(Tokenizer &callerTok) + { + do { ++ auto tok = callerTok; ++ + ParseBws(tok); // Bug 4492: IBM_HTTP_Server sends SP after chunk-size + + if (!tok.skip(';')) +@@ -145,6 +152,7 @@ Http::One::TeChunkedParser::parseChunkExtensions(Tokenizer &tok) + + parseOneChunkExtension(tok); + buf_ = tok.remaining(); // got one extension ++ callerTok = tok; + } while (true); + } + +@@ -158,11 +166,14 @@ Http::One::ChunkExtensionValueParser::Ignore(Tokenizer &tok, const SBuf &extName + /// Parses a single chunk-ext list element: + /// chunk-ext = *( BWS ";" BWS chunk-ext-name [ BWS "=" BWS chunk-ext-val ] ) + void +-Http::One::TeChunkedParser::parseOneChunkExtension(Tokenizer &tok) ++Http::One::TeChunkedParser::parseOneChunkExtension(Tokenizer &callerTok) + { ++ auto tok = callerTok; ++ + ParseBws(tok); // Bug 4492: ICAP servers send SP before chunk-ext-name + + const auto extName = tok.prefix("chunk-ext-name", CharacterSet::TCHAR); ++ callerTok = tok; // in case we determine that this is a valueless chunk-ext + + ParseBws(tok); + +@@ -176,6 +187,8 @@ Http::One::TeChunkedParser::parseOneChunkExtension(Tokenizer &tok) + customExtensionValueParser->parse(tok, extName); + else + ChunkExtensionValueParser::Ignore(tok, extName); ++ ++ callerTok = tok; + } + + bool +@@ -209,7 +222,7 @@ Http::One::TeChunkedParser::parseChunkEnd(Tokenizer &tok) + Must(theLeftBodySize == 0); // Should(), really + + try { +- skipLineTerminator(tok); ++ tok.skipRequired("chunk CRLF", Http1::CrLf()); + buf_ = tok.remaining(); // parse checkpoint + theChunkSize = 0; // done with the current chunk + parsingStage_ = Http1::HTTP_PARSE_CHUNK_SZ; +diff --git a/src/parser/Tokenizer.cc b/src/parser/Tokenizer.cc +index a8a9407..65f46b9 100644 +--- a/src/parser/Tokenizer.cc ++++ b/src/parser/Tokenizer.cc +@@ -147,6 +147,18 @@ Parser::Tokenizer::skipAll(const CharacterSet &tokenChars) + return success(prefixLen); + } + ++void ++Parser::Tokenizer::skipRequired(const char *description, const SBuf &tokenToSkip) ++{ ++ if (skip(tokenToSkip) || tokenToSkip.isEmpty()) ++ return; ++ ++ if (tokenToSkip.startsWith(buf_)) ++ throw InsufficientInput(); ++ ++ throw TextException(ToSBuf("cannot skip ", description), Here()); ++} ++ + bool + Parser::Tokenizer::skipOne(const CharacterSet &chars) + { +diff --git a/src/parser/Tokenizer.h b/src/parser/Tokenizer.h +index 268074f..5255fb0 100644 +--- a/src/parser/Tokenizer.h ++++ b/src/parser/Tokenizer.h +@@ -115,6 +115,13 @@ public: + */ + SBuf::size_type skipAll(const CharacterSet &discardables); + ++ /** skips a given character sequence (string); ++ * does nothing if the sequence is empty ++ * ++ * \throws exception on mismatching prefix or InsufficientInput ++ */ ++ void skipRequired(const char *description, const SBuf &tokenToSkip); ++ + /** Removes a single trailing character from the set. + * + * \return whether a character was removed diff -Nru squid-5.7/debian/patches/CVE-2023-46847.patch squid-5.7/debian/patches/CVE-2023-46847.patch --- squid-5.7/debian/patches/CVE-2023-46847.patch 1970-01-01 00:00:00.000000000 +0000 +++ squid-5.7/debian/patches/CVE-2023-46847.patch 2024-03-05 22:14:44.000000000 +0000 @@ -0,0 +1,33 @@ +From: Markus Koschany +Date: Mon, 19 Feb 2024 12:10:30 +0100 +Subject: CVE-2023-46847 + +Bug-Debian: https://bugs.debian.org/1055250 +Origin: http://www.squid-cache.org/Versions/v5/SQUID-2023_3.patch +--- + src/auth/digest/Config.cc | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/src/auth/digest/Config.cc b/src/auth/digest/Config.cc +index 6c6f6a6..c80f384 100644 +--- a/src/auth/digest/Config.cc ++++ b/src/auth/digest/Config.cc +@@ -844,11 +844,15 @@ Auth::Digest::Config::decode(char const *proxy_auth, const HttpRequest *request, + break; + + case DIGEST_NC: +- if (value.size() != 8) { ++ if (value.size() == 8) { ++ // for historical reasons, the nc value MUST be exactly 8 bytes ++ static_assert(sizeof(digest_request->nc) == 8 + 1, "bad nc buffer size"); ++ xstrncpy(digest_request->nc, value.rawBuf(), value.size() + 1); ++ debugs(29, 9, "Found noncecount '" << digest_request->nc << "'"); ++ } else { + debugs(29, 9, "Invalid nc '" << value << "' in '" << temp << "'"); ++ digest_request->nc[0] = 0; + } +- xstrncpy(digest_request->nc, value.rawBuf(), value.size() + 1); +- debugs(29, 9, "Found noncecount '" << digest_request->nc << "'"); + break; + + case DIGEST_CNONCE: diff -Nru squid-5.7/debian/patches/CVE-2023-46848.patch squid-5.7/debian/patches/CVE-2023-46848.patch --- squid-5.7/debian/patches/CVE-2023-46848.patch 1970-01-01 00:00:00.000000000 +0000 +++ squid-5.7/debian/patches/CVE-2023-46848.patch 2024-03-05 22:14:44.000000000 +0000 @@ -0,0 +1,37 @@ +From: Markus Koschany +Date: Mon, 19 Feb 2024 22:14:27 +0100 +Subject: CVE-2023-46848 + +Bug-Debian: https://bugs.debian.org/1055251 +Origin: http://www.squid-cache.org/Versions/v5/SQUID-2023_5.patch +--- + src/acl/external/eDirectory_userip/ext_edirectory_userip_acl.cc | 2 +- + src/anyp/Uri.cc | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/acl/external/eDirectory_userip/ext_edirectory_userip_acl.cc b/src/acl/external/eDirectory_userip/ext_edirectory_userip_acl.cc +index 49f6fb8..8a904c4 100644 +--- a/src/acl/external/eDirectory_userip/ext_edirectory_userip_acl.cc ++++ b/src/acl/external/eDirectory_userip/ext_edirectory_userip_acl.cc +@@ -1612,7 +1612,7 @@ MainSafe(int argc, char **argv) + /* BINARY DEBUGGING * + local_printfx("while() -> bufa[%" PRIuSIZE "]: %s", k, bufa); + for (i = 0; i < k; ++i) +- local_printfx("%02X", bufa[i]); ++ local_printfx("%02X", static_cast(static_cast(bufa[i]))); + local_printfx("\n"); + * BINARY DEBUGGING */ + /* Check for CRLF */ +diff --git a/src/anyp/Uri.cc b/src/anyp/Uri.cc +index 7ccad93..848a773 100644 +--- a/src/anyp/Uri.cc ++++ b/src/anyp/Uri.cc +@@ -70,7 +70,7 @@ AnyP::Uri::Encode(const SBuf &buf, const CharacterSet &ignore) + while (!tk.atEnd()) { + // TODO: Add Tokenizer::parseOne(void). + const auto ch = tk.remaining()[0]; +- output.appendf("%%%02X", static_cast(ch)); // TODO: Optimize using a table ++ output.appendf("%%%02X", static_cast(static_cast(ch))); // TODO: Optimize using a table + (void)tk.skip(ch); + + if (tk.prefix(goodSection, ignore)) diff -Nru squid-5.7/debian/patches/CVE-2023-49285.patch squid-5.7/debian/patches/CVE-2023-49285.patch --- squid-5.7/debian/patches/CVE-2023-49285.patch 1970-01-01 00:00:00.000000000 +0000 +++ squid-5.7/debian/patches/CVE-2023-49285.patch 2024-03-05 22:14:44.000000000 +0000 @@ -0,0 +1,27 @@ +From: Markus Koschany +Date: Mon, 19 Feb 2024 12:17:10 +0100 +Subject: CVE-2023-49285 + +Origin: http://www.squid-cache.org/Versions/v5/SQUID-2023_7.patch +--- + lib/rfc1123.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/lib/rfc1123.c b/lib/rfc1123.c +index 5fe17df..71931a6 100644 +--- a/lib/rfc1123.c ++++ b/lib/rfc1123.c +@@ -50,7 +50,13 @@ make_month(const char *s) + char month[3]; + + month[0] = xtoupper(*s); ++ if (!month[0]) ++ return -1; // protects *(s + 1) below ++ + month[1] = xtolower(*(s + 1)); ++ if (!month[1]) ++ return -1; // protects *(s + 2) below ++ + month[2] = xtolower(*(s + 2)); + + for (i = 0; i < 12; i++) diff -Nru squid-5.7/debian/patches/CVE-2023-49286.patch squid-5.7/debian/patches/CVE-2023-49286.patch --- squid-5.7/debian/patches/CVE-2023-49286.patch 1970-01-01 00:00:00.000000000 +0000 +++ squid-5.7/debian/patches/CVE-2023-49286.patch 2024-03-05 22:14:44.000000000 +0000 @@ -0,0 +1,72 @@ +From: Markus Koschany +Date: Mon, 19 Feb 2024 12:18:36 +0100 +Subject: CVE-2023-49286 + +Origin: http://www.squid-cache.org/Versions/v6/SQUID-2023_8.patch +--- + src/ipc.cc | 33 +++++++++++++++++++++++++++------ + 1 file changed, 27 insertions(+), 6 deletions(-) + +diff --git a/src/ipc.cc b/src/ipc.cc +index 45cab52..f6cb82c 100644 +--- a/src/ipc.cc ++++ b/src/ipc.cc +@@ -19,6 +19,12 @@ + #include "SquidConfig.h" + #include "SquidIpc.h" + #include "tools.h" ++#include ++ ++#if HAVE_UNISTD_H ++#include ++#endif ++ + + static const char *hello_string = "hi there\n"; + #ifndef HELLO_BUF_SZ +@@ -365,6 +371,22 @@ ipcCreate(int type, const char *prog, const char *const args[], const char *name + } + + PutEnvironment(); ++ ++ // A dup(2) wrapper that reports and exits the process on errors. The ++ // exiting logic is only suitable for this child process context. ++ const auto dupOrExit = [prog,name](const int oldFd) { ++ const auto newFd = dup(oldFd); ++ if (newFd < 0) { ++ const auto savedErrno = errno; ++ debugs(54, DBG_CRITICAL, "ERROR: Helper process initialization failure: " << name << ++ Debug::Extra << "helper (CHILD) PID: " << getpid() << ++ Debug::Extra << "helper program name: " << prog << ++ Debug::Extra << "dup(2) system call error for FD " << oldFd << ": " << xstrerr(savedErrno)); ++ _exit(EXIT_FAILURE); ++ } ++ return newFd; ++ }; ++ + /* + * This double-dup stuff avoids problems when one of + * crfd, cwfd, or debug_log are in the rage 0-2. +@@ -372,17 +394,16 @@ ipcCreate(int type, const char *prog, const char *const args[], const char *name + + do { + /* First make sure 0-2 is occupied by something. Gets cleaned up later */ +- x = dup(crfd); +- assert(x > -1); +- } while (x < 3 && x > -1); ++ x = dupOrExit(crfd); ++ } while (x < 3); + + close(x); + +- t1 = dup(crfd); ++ t1 = dupOrExit(crfd); + +- t2 = dup(cwfd); ++ t2 = dupOrExit(cwfd); + +- t3 = dup(fileno(debug_log)); ++ t3 = dupOrExit(fileno(debug_log)); + + assert(t1 > 2 && t2 > 2 && t3 > 2); + diff -Nru squid-5.7/debian/patches/CVE-2023-50269.patch squid-5.7/debian/patches/CVE-2023-50269.patch --- squid-5.7/debian/patches/CVE-2023-50269.patch 1970-01-01 00:00:00.000000000 +0000 +++ squid-5.7/debian/patches/CVE-2023-50269.patch 2024-03-05 22:14:44.000000000 +0000 @@ -0,0 +1,61 @@ +From: Markus Koschany +Date: Mon, 19 Feb 2024 12:31:13 +0100 +Subject: CVE-2023-50269 + +Bug-Debian: https://bugs.debian.org/1058721 +Origin: http://www.squid-cache.org/Versions/v5/SQUID-2023_10.patch +--- + src/ClientRequestContext.h | 4 ++++ + src/client_side_request.cc | 17 +++++++++++++++-- + 2 files changed, 19 insertions(+), 2 deletions(-) + +diff --git a/src/ClientRequestContext.h b/src/ClientRequestContext.h +index 55a7a43..94a8700 100644 +--- a/src/ClientRequestContext.h ++++ b/src/ClientRequestContext.h +@@ -80,6 +80,10 @@ public: + #endif + ErrorState *error; ///< saved error page for centralized/delayed processing + bool readNextRequest; ///< whether Squid should read after error handling ++ ++#if FOLLOW_X_FORWARDED_FOR ++ size_t currentXffHopNumber = 0; ///< number of X-Forwarded-For header values processed so far ++#endif + }; + + #endif /* SQUID_CLIENTREQUESTCONTEXT_H */ +diff --git a/src/client_side_request.cc b/src/client_side_request.cc +index 0a4e2c2..ed5e947 100644 +--- a/src/client_side_request.cc ++++ b/src/client_side_request.cc +@@ -81,6 +81,11 @@ + static const char *const crlf = "\r\n"; + + #if FOLLOW_X_FORWARDED_FOR ++ ++#if !defined(SQUID_X_FORWARDED_FOR_HOP_MAX) ++#define SQUID_X_FORWARDED_FOR_HOP_MAX 64 ++#endif ++ + static void clientFollowXForwardedForCheck(Acl::Answer answer, void *data); + #endif /* FOLLOW_X_FORWARDED_FOR */ + +@@ -486,8 +491,16 @@ clientFollowXForwardedForCheck(Acl::Answer answer, void *data) + /* override the default src_addr tested if we have to go deeper than one level into XFF */ + Filled(calloutContext->acl_checklist)->src_addr = request->indirect_client_addr; + } +- calloutContext->acl_checklist->nonBlockingCheck(clientFollowXForwardedForCheck, data); +- return; ++ if (++calloutContext->currentXffHopNumber < SQUID_X_FORWARDED_FOR_HOP_MAX) { ++ calloutContext->acl_checklist->nonBlockingCheck(clientFollowXForwardedForCheck, data); ++ return; ++ } ++ const auto headerName = Http::HeaderLookupTable.lookup(Http::HdrType::X_FORWARDED_FOR).name; ++ debugs(28, DBG_CRITICAL, "ERROR: Ignoring trailing " << headerName << " addresses" << ++ Debug::Extra << "addresses allowed by follow_x_forwarded_for: " << calloutContext->currentXffHopNumber << ++ Debug::Extra << "last/accepted address: " << request->indirect_client_addr << ++ Debug::Extra << "ignored trailing addresses: " << request->x_forwarded_for_iterator); ++ // fall through to resume clientAccessCheck() processing + } + } + diff -Nru squid-5.7/debian/patches/CVE-2024-23638.patch squid-5.7/debian/patches/CVE-2024-23638.patch --- squid-5.7/debian/patches/CVE-2024-23638.patch 1970-01-01 00:00:00.000000000 +0000 +++ squid-5.7/debian/patches/CVE-2024-23638.patch 2024-03-05 22:14:44.000000000 +0000 @@ -0,0 +1,21 @@ +From: Markus Koschany +Date: Mon, 19 Feb 2024 12:32:00 +0100 +Subject: CVE-2024-23638 + +Origin: http://www.squid-cache.org/Versions/v5/SQUID-2023_11.patch +--- + src/cache_manager.cc | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/cache_manager.cc b/src/cache_manager.cc +index 74b049a..d630784 100644 +--- a/src/cache_manager.cc ++++ b/src/cache_manager.cc +@@ -326,7 +326,6 @@ CacheManager::start(const Comm::ConnectionPointer &client, HttpRequest *request, + err->url = xstrdup(entry->url()); + err->detailError(new ExceptionErrorDetail(Here().id())); + errorAppendEntry(entry, err); +- entry->expires = squid_curtime; + return; + } + diff -Nru squid-5.7/debian/patches/CVE-2024-25111.patch squid-5.7/debian/patches/CVE-2024-25111.patch --- squid-5.7/debian/patches/CVE-2024-25111.patch 1970-01-01 00:00:00.000000000 +0000 +++ squid-5.7/debian/patches/CVE-2024-25111.patch 2024-03-05 22:14:44.000000000 +0000 @@ -0,0 +1,399 @@ +From: Markus Koschany +Date: Tue, 5 Mar 2024 16:35:19 +0100 +Subject: CVE-2024-25111 + +Origin: http://www.squid-cache.org/Versions/v6/SQUID-2024_1.patch +--- + src/SquidMath.h | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- + src/http.cc | 110 +++++++++++++++++++++++++---------- + src/http.h | 15 ++--- + 3 files changed, 256 insertions(+), 44 deletions(-) + +diff --git a/src/SquidMath.h b/src/SquidMath.h +index f4ec462..867f7fe 100644 +--- a/src/SquidMath.h ++++ b/src/SquidMath.h +@@ -1,13 +1,21 @@ + /* +- * Copyright (C) 1996-2022 The Squid Software Foundation and contributors ++ * Copyright (C) 1996-2023 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. + */ + +-#ifndef _SQUID_SRC_SQUIDMATH_H +-#define _SQUID_SRC_SQUIDMATH_H ++#ifndef SQUID_SRC_SQUIDMATH_H ++#define SQUID_SRC_SQUIDMATH_H ++ ++#include "base/forward.h" ++#include "base/TypeTraits.h" ++ ++#include ++#include ++ ++// TODO: Move to src/base/Math.h and drop the Math namespace + + /* Math functions we define locally for Squid */ + namespace Math +@@ -21,5 +29,164 @@ double doubleAverage(const double, const double, int, const int); + + } // namespace Math + +-#endif /* _SQUID_SRC_SQUIDMATH_H */ ++// If Sum() performance becomes important, consider using GCC and clang ++// built-ins like __builtin_add_overflow() instead of manual overflow checks. ++ ++/// detects a pair of unsigned types ++/// reduces code duplication in declarations further below ++template ++using AllUnsigned = typename std::conditional< ++ std::is_unsigned::value && std::is_unsigned::value, ++ std::true_type, ++ std::false_type ++ >::type; ++ ++// TODO: Replace with std::cmp_less() after migrating to C++20. ++/// whether integer a is less than integer b, with correct overflow handling ++template ++constexpr bool ++Less(const A a, const B b) { ++ // The casts below make standard C++ integer conversions explicit. They ++ // quell compiler warnings about signed/unsigned comparison. The first two ++ // lines exclude different-sign a and b, making the casts/comparison safe. ++ using AB = typename std::common_type::type; ++ return ++ (a >= 0 && b < 0) ? false : ++ (a < 0 && b >= 0) ? true : ++ /* (a >= 0) == (b >= 0) */ static_cast(a) < static_cast(b); ++} ++ ++/// ensure that T is supported by NaturalSum() and friends ++template ++constexpr void ++AssertNaturalType() ++{ ++ static_assert(std::numeric_limits::is_bounded, "std::numeric_limits::max() is meaningful"); ++ static_assert(std::numeric_limits::is_exact, "no silent loss of precision"); ++ static_assert(!std::is_enum::value, "no silent creation of non-enumerated values"); ++} ++ ++// TODO: Investigate whether this optimization can be expanded to [signed] types ++// A and B when std::numeric_limits::is_modulo is true. ++/// This IncreaseSumInternal() overload is optimized for speed. ++/// \returns a non-overflowing sum of the two unsigned arguments (or nothing) ++/// \prec both argument types are unsigned ++template ::value, int> = 0> ++std::optional ++IncreaseSumInternal(const A a, const B b) { ++ // paranoid: AllUnsigned precondition established that already ++ static_assert(std::is_unsigned::value, "AllUnsigned dispatch worked for A"); ++ static_assert(std::is_unsigned::value, "AllUnsigned dispatch worked for B"); ++ ++ AssertNaturalType(); ++ AssertNaturalType(); ++ AssertNaturalType(); ++ ++ // we should only be called by IncreaseSum(); it forces integer promotion ++ static_assert(std::is_same::value, "a will not be promoted"); ++ static_assert(std::is_same::value, "b will not be promoted"); ++ // and without integer promotions, a sum of unsigned integers is unsigned ++ static_assert(std::is_unsigned::value, "a+b is unsigned"); ++ ++ // with integer promotions ruled out, a or b can only undergo integer ++ // conversion to the higher rank type (A or B, we do not know which) ++ using AB = typename std::common_type::type; ++ static_assert(std::is_same::value || std::is_same::value, "no unexpected conversions"); ++ static_assert(std::is_same::value, "lossless assignment"); ++ const AB sum = a + b; ++ ++ static_assert(std::numeric_limits::is_modulo, "we can detect overflows"); ++ // 1. modulo math: overflowed sum is smaller than any of its operands ++ // 2. the sum may overflow S (i.e. the return base type) ++ // We do not need Less() here because we compare promoted unsigned types. ++ return (sum >= a && sum <= std::numeric_limits::max()) ? ++ std::optional(sum) : std::optional(); ++} ++ ++/// This IncreaseSumInternal() overload supports a larger variety of types. ++/// \returns a non-overflowing sum of the two arguments (or nothing) ++/// \returns nothing if at least one of the arguments is negative ++/// \prec at least one of the argument types is signed ++template ::value, int> = 0> ++std::optional constexpr ++IncreaseSumInternal(const A a, const B b) { ++ AssertNaturalType(); ++ AssertNaturalType(); ++ AssertNaturalType(); ++ ++ // we should only be called by IncreaseSum() that does integer promotion ++ static_assert(std::is_same::value, "a will not be promoted"); ++ static_assert(std::is_same::value, "b will not be promoted"); ++ ++ return ++ // We could support a non-under/overflowing sum of negative numbers, but ++ // our callers use negative values specially (e.g., for do-not-use or ++ // do-not-limit settings) and are not supposed to do math with them. ++ (a < 0 || b < 0) ? std::optional() : ++ // To avoid undefined behavior of signed overflow, we must not compute ++ // the raw a+b sum if it may overflow. When A is not B, a or b undergoes ++ // (safe for non-negatives) integer conversion in these expressions, so ++ // we do not know the resulting a+b type AB and its maximum. We must ++ // also detect subsequent casting-to-S overflows. ++ // Overflow condition: (a + b > maxAB) or (a + b > maxS). ++ // A is an integer promotion of S, so maxS <= maxA <= maxAB. ++ // Since maxS <= maxAB, it is sufficient to just check: a + b > maxS, ++ // which is the same as the overflow-safe condition here: maxS - a < b. ++ // Finally, (maxS - a) cannot overflow because a is not negative and ++ // cannot underflow because a is a promotion of s: 0 <= a <= maxS. ++ Less(std::numeric_limits::max() - a, b) ? std::optional() : ++ std::optional(a + b); ++} ++ ++/// argument pack expansion termination for IncreaseSum() ++template ++std::optional ++IncreaseSum(const S s, const T t) ++{ ++ // Force (always safe) integer promotions now, to give std::enable_if_t<> ++ // promoted types instead of entering IncreaseSumInternal(s,t) ++ // but getting a _signed_ promoted value of s or t in s + t. ++ return IncreaseSumInternal(+s, +t); ++} ++ ++/// \returns a non-overflowing sum of the arguments (or nothing) ++template ++std::optional ++IncreaseSum(const S sum, const T t, const Args... args) { ++ if (const auto head = IncreaseSum(sum, t)) { ++ return IncreaseSum(head.value(), args...); ++ } else { ++ // std::optional() triggers bogus -Wmaybe-uninitialized warnings in GCC v10.3 ++ return std::nullopt; ++ } ++} ++ ++/// \returns an exact, non-overflowing sum of the arguments (or nothing) ++template ++std::optional ++NaturalSum(const Args... args) { ++ return IncreaseSum(0, args...); ++} ++ ++/// Safely resets the given variable to NaturalSum() of the given arguments. ++/// If the sum overflows, resets to variable's maximum possible value. ++/// \returns the new variable value (like an assignment operator would) ++template ++S ++SetToNaturalSumOrMax(S &var, const Args... args) ++{ ++ var = NaturalSum(args...).value_or(std::numeric_limits::max()); ++ return var; ++} ++ ++/// converts a given non-negative integer into an integer of a given type ++/// without loss of information or undefined behavior ++template ++Result ++NaturalCast(const Source s) ++{ ++ return NaturalSum(s).value(); ++} ++ ++#endif /* SQUID_SRC_SQUIDMATH_H */ + +diff --git a/src/http.cc b/src/http.cc +index 7c9ae70..d3b8bcc 100644 +--- a/src/http.cc ++++ b/src/http.cc +@@ -59,6 +59,7 @@ + #include "StrList.h" + #include "tools.h" + #include "util.h" ++#include "SquidMath.h" + + #if USE_AUTH + #include "auth/UserRequest.h" +@@ -1235,18 +1236,27 @@ HttpStateData::readReply(const CommIoCbParams &io) + * Plus, it breaks our lame *HalfClosed() detection + */ + +- Must(maybeMakeSpaceAvailable(true)); +- CommIoCbParams rd(this); // will be expanded with ReadNow results +- rd.conn = io.conn; +- rd.size = entry->bytesWanted(Range(0, inBuf.spaceSize())); ++ const auto moreDataPermission = canBufferMoreReplyBytes(); ++ if (!moreDataPermission) { ++ abortTransaction("ready to read required data, but the read buffer is full and cannot be drained"); ++ return; ++ } ++ ++ const auto readSizeMax = maybeMakeSpaceAvailable(moreDataPermission.value()); ++ // TODO: Move this logic inside maybeMakeSpaceAvailable(): ++ const auto readSizeWanted = readSizeMax ? entry->bytesWanted(Range(0, readSizeMax)) : 0; + +- if (rd.size <= 0) { ++ if (readSizeWanted <= 0) { + assert(entry->mem_obj); + AsyncCall::Pointer nilCall; + entry->mem_obj->delayRead(DeferredRead(readDelayed, this, CommRead(io.conn, NULL, 0, nilCall))); + return; + } + ++ ++ CommIoCbParams rd(this); // will be expanded with ReadNow results ++ rd.conn = io.conn; ++ rd.size = readSizeWanted; + switch (Comm::ReadNow(rd, inBuf)) { + case Comm::INPROGRESS: + if (inBuf.isEmpty()) +@@ -1617,8 +1627,10 @@ HttpStateData::maybeReadVirginBody() + if (!Comm::IsConnOpen(serverConnection) || fd_table[serverConnection->fd].closing()) + return; + +- if (!maybeMakeSpaceAvailable(false)) ++ if (!canBufferMoreReplyBytes()) { ++ abortTransaction("more response bytes required, but the read buffer is full and cannot be drained"); + return; ++ } + + // XXX: get rid of the do_next_read flag + // check for the proper reasons preventing read(2) +@@ -1636,40 +1648,78 @@ HttpStateData::maybeReadVirginBody() + Comm::Read(serverConnection, call); + } + +-bool +-HttpStateData::maybeMakeSpaceAvailable(bool doGrow) ++/// Desired inBuf capacity based on various capacity preferences/limits: ++/// * a smaller buffer may not hold enough for look-ahead header/body parsers; ++/// * a smaller buffer may result in inefficient tiny network reads; ++/// * a bigger buffer may waste memory; ++/// * a bigger buffer may exceed SBuf storage capabilities (SBuf::maxSize); ++size_t ++HttpStateData::calcReadBufferCapacityLimit() const + { +- // how much we are allowed to buffer +- const int limitBuffer = (flags.headers_parsed ? Config.readAheadGap : Config.maxReplyHeaderSize); +- +- if (limitBuffer < 0 || inBuf.length() >= (SBuf::size_type)limitBuffer) { +- // when buffer is at or over limit already +- debugs(11, 7, "will not read up to " << limitBuffer << ". buffer has (" << inBuf.length() << "/" << inBuf.spaceSize() << ") from " << serverConnection); +- debugs(11, DBG_DATA, "buffer has {" << inBuf << "}"); +- // Process next response from buffer +- processReply(); +- return false; ++ if (!flags.headers_parsed) ++ return Config.maxReplyHeaderSize; ++ ++ // XXX: Our inBuf is not used to maintain the read-ahead gap, and using ++ // Config.readAheadGap like this creates huge read buffers for large ++ // read_ahead_gap values. TODO: Switch to using tcp_recv_bufsize as the ++ // primary read buffer capacity factor. ++ // ++ // TODO: Cannot reuse throwing NaturalCast() here. Consider removing ++ // .value() dereference in NaturalCast() or add/use NaturalCastOrMax(). ++ const auto configurationPreferences = NaturalSum(Config.readAheadGap).value_or(SBuf::maxSize); ++ ++ // TODO: Honor TeChunkedParser look-ahead and trailer parsing requirements ++ // (when explicit configurationPreferences are set too low). ++ ++ return std::min(configurationPreferences, SBuf::maxSize); ++} ++ ++/// The maximum number of virgin reply bytes we may buffer before we violate ++/// the currently configured response buffering limits. ++/// \retval std::nullopt means that no more virgin response bytes can be read ++/// \retval 0 means that more virgin response bytes may be read later ++/// \retval >0 is the number of bytes that can be read now (subject to other constraints) ++std::optional ++HttpStateData::canBufferMoreReplyBytes() const ++{ ++#if USE_ADAPTATION ++ // If we do not check this now, we may say the final "no" prematurely below ++ // because inBuf.length() will decrease as adaptation drains buffered bytes. ++ if (responseBodyBuffer) { ++ debugs(11, 3, "yes, but waiting for adaptation to drain read buffer"); ++ return 0; // yes, we may be able to buffer more (but later) ++ } ++#endif ++ ++ const auto maxCapacity = calcReadBufferCapacityLimit(); ++ if (inBuf.length() >= maxCapacity) { ++ debugs(11, 3, "no, due to a full buffer: " << inBuf.length() << '/' << inBuf.spaceSize() << "; limit: " << maxCapacity); ++ return std::nullopt; // no, configuration prohibits buffering more + } + ++ const auto maxReadSize = maxCapacity - inBuf.length(); // positive ++ debugs(11, 7, "yes, may read up to " << maxReadSize << " into " << inBuf.length() << '/' << inBuf.spaceSize()); ++ return maxReadSize; // yes, can read up to this many bytes (subject to other constraints) ++} ++ ++/// prepare read buffer for reading ++/// \return the maximum number of bytes the caller should attempt to read ++/// \retval 0 means that the caller should delay reading ++size_t ++HttpStateData::maybeMakeSpaceAvailable(const size_t maxReadSize) ++{ + // how much we want to read +- const size_t read_size = calcBufferSpaceToReserve(inBuf.spaceSize(), (limitBuffer - inBuf.length())); ++ const size_t read_size = calcBufferSpaceToReserve(inBuf.spaceSize(), maxReadSize); + +- if (!read_size) { ++ if (read_size < 2) { + debugs(11, 7, "will not read up to " << read_size << " into buffer (" << inBuf.length() << "/" << inBuf.spaceSize() << ") from " << serverConnection); +- return false; ++ return 0; + } + +- // just report whether we could grow or not, do not actually do it +- if (doGrow) +- return (read_size >= 2); +- + // we may need to grow the buffer + inBuf.reserveSpace(read_size); +- debugs(11, 8, (!flags.do_next_read ? "will not" : "may") << +- " read up to " << read_size << " bytes info buf(" << inBuf.length() << "/" << inBuf.spaceSize() << +- ") from " << serverConnection); +- +- return (inBuf.spaceSize() >= 2); // only read if there is 1+ bytes of space available ++ debugs(11, 7, "may read up to " << read_size << " bytes info buffer (" << inBuf.length() << "/" << inBuf.spaceSize() << ") from " << serverConnection); ++ return read_size; + } + + /// called after writing the very last request byte (body, last-chunk, etc) +diff --git a/src/http.h b/src/http.h +index e70cd7e..f7ed40d 100644 +--- a/src/http.h ++++ b/src/http.h +@@ -15,6 +15,8 @@ + #include "http/StateFlags.h" + #include "sbuf/SBuf.h" + ++#include ++ + class FwdState; + class HttpHeader; + class String; +@@ -112,16 +114,9 @@ private: + + void abortTransaction(const char *reason) { abortAll(reason); } // abnormal termination + +- /** +- * determine if read buffer can have space made available +- * for a read. +- * +- * \param grow whether to actually expand the buffer +- * +- * \return whether the buffer can be grown to provide space +- * regardless of whether the grow actually happened. +- */ +- bool maybeMakeSpaceAvailable(bool grow); ++ size_t calcReadBufferCapacityLimit() const; ++ std::optional canBufferMoreReplyBytes() const; ++ size_t maybeMakeSpaceAvailable(size_t maxReadSize); + + // consuming request body + virtual void handleMoreRequestBodyAvailable(); diff -Nru squid-5.7/debian/patches/CVE-2024-25617.patch squid-5.7/debian/patches/CVE-2024-25617.patch --- squid-5.7/debian/patches/CVE-2024-25617.patch 1970-01-01 00:00:00.000000000 +0000 +++ squid-5.7/debian/patches/CVE-2024-25617.patch 2024-03-05 22:14:44.000000000 +0000 @@ -0,0 +1,117 @@ +From: Markus Koschany +Date: Tue, 5 Mar 2024 16:36:54 +0100 +Subject: CVE-2024-25617 + +Origin: http://www.squid-cache.org/Versions/v6/SQUID-2024_2.patch +--- + src/SquidString.h | 11 ++++++++++- + src/cache_cf.cc | 12 ++++++++++++ + src/cf.data.pre | 26 ++++++++++++++++---------- + src/http.cc | 5 +++-- + 4 files changed, 41 insertions(+), 13 deletions(-) + +diff --git a/src/SquidString.h b/src/SquidString.h +index e36cd27..ea613ad 100644 +--- a/src/SquidString.h ++++ b/src/SquidString.h +@@ -140,7 +140,16 @@ private: + + size_type len_ = 0; /* current length */ + +- static const size_type SizeMax_ = 65535; ///< 64K limit protects some fixed-size buffers ++ /// An earlier 64KB limit was meant to protect some fixed-size buffers, but ++ /// (a) we do not know where those buffers are (or whether they still exist) ++ /// (b) too many String users unknowingly exceeded that limit and asserted. ++ /// We are now using a larger limit to reduce the number of (b) cases, ++ /// especially cases where "compact" lists of items grow 50% in size when we ++ /// convert them to canonical form. The new limit is selected to withstand ++ /// concatenation and ~50% expansion of two HTTP headers limited by default ++ /// request_header_max_size and reply_header_max_size settings. ++ static const size_type SizeMax_ = 3*64*1024 - 1; ++ + /// returns true after increasing the first argument by extra if the sum does not exceed SizeMax_ + static bool SafeAdd(size_type &base, size_type extra) { if (extra <= SizeMax_ && base <= SizeMax_ - extra) { base += extra; return true; } return false; } + +diff --git a/src/cache_cf.cc b/src/cache_cf.cc +index 1bae8d3..c04b0b4 100644 +--- a/src/cache_cf.cc ++++ b/src/cache_cf.cc +@@ -950,6 +950,18 @@ configDoConfigure(void) + (uint32_t)Config.maxRequestBufferSize, (uint32_t)Config.maxRequestHeaderSize); + } + ++ // Warn about the dangers of exceeding String limits when manipulating HTTP ++ // headers. Technically, we do not concatenate _requests_, so we could relax ++ // their check, but we keep the two checks the same for simplicity sake. ++ const auto safeRawHeaderValueSizeMax = (String::SizeMaxXXX()+1)/3; ++ // TODO: static_assert(safeRawHeaderValueSizeMax >= 64*1024); // no WARNINGs for default settings ++ if (Config.maxRequestHeaderSize > safeRawHeaderValueSizeMax) ++ debugs(3, DBG_CRITICAL, "WARNING: Increasing request_header_max_size beyond " << safeRawHeaderValueSizeMax << ++ " bytes makes Squid more vulnerable to denial-of-service attacks; configured value: " << Config.maxRequestHeaderSize << " bytes"); ++ if (Config.maxReplyHeaderSize > safeRawHeaderValueSizeMax) ++ debugs(3, DBG_CRITICAL, "WARNING: Increasing reply_header_max_size beyond " << safeRawHeaderValueSizeMax << ++ " bytes makes Squid more vulnerable to denial-of-service attacks; configured value: " << Config.maxReplyHeaderSize << " bytes"); ++ + /* + * Disable client side request pipelining if client_persistent_connections OFF. + * Waste of resources queueing any pipelined requests when the first will close the connection. +diff --git a/src/cf.data.pre b/src/cf.data.pre +index 2e47f49..2132ba7 100644 +--- a/src/cf.data.pre ++++ b/src/cf.data.pre +@@ -6497,11 +6497,14 @@ TYPE: b_size_t + DEFAULT: 64 KB + LOC: Config.maxRequestHeaderSize + DOC_START +- This specifies the maximum size for HTTP headers in a request. +- Request headers are usually relatively small (about 512 bytes). +- Placing a limit on the request header size will catch certain +- bugs (for example with persistent connections) and possibly +- buffer-overflow or denial-of-service attacks. ++ This directives limits the header size of a received HTTP request ++ (including request-line). Increasing this limit beyond its 64 KB default ++ exposes certain old Squid code to various denial-of-service attacks. This ++ limit also applies to received FTP commands. ++ ++ This limit has no direct affect on Squid memory consumption. ++ ++ Squid does not check this limit when sending requests. + DOC_END + + NAME: reply_header_max_size +@@ -6510,11 +6513,14 @@ TYPE: b_size_t + DEFAULT: 64 KB + LOC: Config.maxReplyHeaderSize + DOC_START +- This specifies the maximum size for HTTP headers in a reply. +- Reply headers are usually relatively small (about 512 bytes). +- Placing a limit on the reply header size will catch certain +- bugs (for example with persistent connections) and possibly +- buffer-overflow or denial-of-service attacks. ++ This directives limits the header size of a received HTTP response ++ (including status-line). Increasing this limit beyond its 64 KB default ++ exposes certain old Squid code to various denial-of-service attacks. This ++ limit also applies to FTP command responses. ++ ++ Squid also checks this limit when loading hit responses from disk cache. ++ ++ Squid does not check this limit when sending responses. + DOC_END + + NAME: request_body_max_size +diff --git a/src/http.cc b/src/http.cc +index d3b8bcc..9992819 100644 +--- a/src/http.cc ++++ b/src/http.cc +@@ -1976,8 +1976,9 @@ HttpStateData::httpBuildRequestHeader(HttpRequest * request, + + String strFwd = hdr_in->getList(Http::HdrType::X_FORWARDED_FOR); + +- // if we cannot double strFwd size, then it grew past 50% of the limit +- if (!strFwd.canGrowBy(strFwd.size())) { ++ // Detect unreasonably long header values. And paranoidly check String ++ // limits: a String ought to accommodate two reasonable-length values. ++ if (strFwd.size() > 32*1024 || !strFwd.canGrowBy(strFwd.size())) { + // There is probably a forwarding loop with Via detection disabled. + // If we do nothing, String will assert on overflow soon. + // TODO: Terminate all transactions with huge XFF? diff -Nru squid-5.7/debian/patches/series squid-5.7/debian/patches/series --- squid-5.7/debian/patches/series 2023-04-28 06:35:27.000000000 +0000 +++ squid-5.7/debian/patches/series 2024-03-05 22:14:44.000000000 +0000 @@ -4,3 +4,13 @@ 0002-Change-default-file-locations-for-debian.patch 0003-installed-binary-for-debian-ci.patch 0005-Use-RuntimeDirectory-to-create-run-squid.patch +CVE-2023-46724.patch +CVE-2023-46846.patch +CVE-2023-46847.patch +CVE-2023-46848.patch +CVE-2023-49285.patch +CVE-2023-49286.patch +CVE-2023-50269.patch +CVE-2024-23638.patch +CVE-2024-25111.patch +CVE-2024-25617.patch