Compare commits

...

10 Commits

Author SHA1 Message Date
openeuler-ci-bot
3387afcddf
!165 fix CVE-2024-45802
From: @xinghe_1 
Reviewed-by: @jiangheng12 
Signed-off-by: @jiangheng12
2024-10-29 07:32:03 +00:00
xh
9ea73ab45e fix CVE-2024-45802 2024-10-29 05:55:29 +00:00
openeuler-ci-bot
cbb3ba32d1
!160 fix CVE-2024-25111
From: @xinghe_1 
Reviewed-by: @jiangheng12 
Signed-off-by: @jiangheng12
2024-09-23 03:17:16 +00:00
xh
2e9b788a12 fix CVE-2024-25111 2024-09-19 07:42:33 +00:00
openeuler-ci-bot
b3ffde3e0d
!149 fix CVE-2024-37894
From: @xinghe_1 
Reviewed-by: @renmingshuai 
Signed-off-by: @renmingshuai
2024-06-27 06:38:51 +00:00
xh
e8a9d9d09d fix CVE-2024-37894 2024-06-26 03:51:16 +00:00
openeuler-ci-bot
7101e68198
!143 fix CVE-2024-25617
From: @xinghe_1 
Reviewed-by: @robertxw 
Signed-off-by: @robertxw
2024-02-20 08:38:10 +00:00
xh
7614078a30 fix CVE-2024-25617 2024-02-20 14:45:06 +08:00
openeuler-ci-bot
87ed4bdb7c
!127 fix CVE-2024-23638
From: @xinghe_1 
Reviewed-by: @robertxw 
Signed-off-by: @robertxw
2024-01-25 11:21:25 +00:00
xinghe
e4498955c2 fix CVE-2024-23638 2024-01-25 08:29:24 +00:00
5 changed files with 637 additions and 3 deletions

View File

@ -0,0 +1,36 @@
From 5bede3305cabb9ac19babecf3ebaf64f43f7b53e Mon Sep 17 00:00:00 2001
From: Alex Rousskov <rousskov@measurement-factory.com>
Date: Sun, 12 Nov 2023 09:33:20 +0000
Subject: [PATCH] Do not update StoreEntry expiration after errorAppendEntry()
(#1580)
errorAppendEntry() is responsible for setting entry expiration times,
which it does by calling StoreEntry::storeErrorResponse() that calls
StoreEntry::negativeCache().
This change was triggered by a vulnerability report by Joshua Rogers at
https://megamansec.github.io/Squid-Security-Audit/cache-uaf.html where
it was filed as "Use-After-Free in Cache Manager Errors". The reported
"use after free" vulnerability was unknowingly addressed by 2022 commit
1fa761a that removed excessively long "reentrant" store_client calls
responsible for the disappearance of the properly locked StoreEntry in
this (and probably other) contexts.
Conflict: context adapt
Reference: https://github.com/squid-cache/squid/commit/5bede3305cabb9ac19babecf3ebaf64f43f7b53e
---
src/cache_manager.cc | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/cache_manager.cc b/src/cache_manager.cc
index b5a9cbecd33..08445a517a9 100644
--- a/src/cache_manager.cc
+++ b/src/cache_manager.cc
@@ -306,7 +306,6 @@ CacheManager::start(const Comm::ConnectionPointer &client, HttpRequest *request,
const auto err = new ErrorState(ERR_INVALID_URL, Http::scNotFound, request);
err->url = xstrdup(entry->url());
errorAppendEntry(entry, err);
- entry->expires = squid_curtime;
return;
}

View File

@ -0,0 +1,394 @@
From 4658d0fc049738c2e6cd25fc0af10e820cf4c11a Mon Sep 17 00:00:00 2001
From: Markus Koschany <apo@debian.org>
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
Conflict: NA
Reference: https://launchpad.net/ubuntu/+archive/primary/+sourcefiles/squid/4.10-1ubuntu1.10/squid_4.10-1ubuntu1.10.debian.tar.xz
---
src/SquidMath.h | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
src/http.cc | 110 +++++++++++++++++++++++++----------
src/http.h | 15 ++---
3 files changed, 256 insertions(+), 44 deletions(-)
--- a/src/SquidMath.h
+++ b/src/SquidMath.h
@@ -1,13 +1,18 @@
/*
- * Copyright (C) 1996-2019 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 <limits>
+#include <optional>
+
+// TODO: Move to src/base/Math.h and drop the Math namespace
/* Math functions we define locally for Squid */
namespace Math
@@ -21,5 +26,164 @@ double doubleAverage(const double, const
} // 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 <typename T, typename U>
+using AllUnsigned = typename std::conditional<
+ std::is_unsigned<T>::value && std::is_unsigned<U>::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 <typename A, typename B>
+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<A, B>::type;
+ return
+ (a >= 0 && b < 0) ? false :
+ (a < 0 && b >= 0) ? true :
+ /* (a >= 0) == (b >= 0) */ static_cast<AB>(a) < static_cast<AB>(b);
+}
+
+/// ensure that T is supported by NaturalSum() and friends
+template<typename T>
+constexpr void
+AssertNaturalType()
+{
+ static_assert(std::numeric_limits<T>::is_bounded, "std::numeric_limits<T>::max() is meaningful");
+ static_assert(std::numeric_limits<T>::is_exact, "no silent loss of precision");
+ static_assert(!std::is_enum<T>::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<decltype(A(0)+B(0))>::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 <typename S, typename A, typename B, std::enable_if_t<AllUnsigned<A,B>::value, int> = 0>
+std::optional<S>
+IncreaseSumInternal(const A a, const B b) {
+ // paranoid: AllUnsigned<A,B> precondition established that already
+ static_assert(std::is_unsigned<A>::value, "AllUnsigned dispatch worked for A");
+ static_assert(std::is_unsigned<B>::value, "AllUnsigned dispatch worked for B");
+
+ AssertNaturalType<S>();
+ AssertNaturalType<A>();
+ AssertNaturalType<B>();
+
+ // we should only be called by IncreaseSum(); it forces integer promotion
+ static_assert(std::is_same<A, decltype(+a)>::value, "a will not be promoted");
+ static_assert(std::is_same<B, decltype(+b)>::value, "b will not be promoted");
+ // and without integer promotions, a sum of unsigned integers is unsigned
+ static_assert(std::is_unsigned<decltype(a+b)>::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<A, B>::type;
+ static_assert(std::is_same<AB, A>::value || std::is_same<AB, B>::value, "no unexpected conversions");
+ static_assert(std::is_same<AB, decltype(a+b)>::value, "lossless assignment");
+ const AB sum = a + b;
+
+ static_assert(std::numeric_limits<AB>::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<S>::max()) ?
+ std::optional<S>(sum) : std::optional<S>();
+}
+
+/// 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 <typename S, typename A, typename B, std::enable_if_t<!AllUnsigned<A,B>::value, int> = 0>
+std::optional<S> constexpr
+IncreaseSumInternal(const A a, const B b) {
+ AssertNaturalType<S>();
+ AssertNaturalType<A>();
+ AssertNaturalType<B>();
+
+ // we should only be called by IncreaseSum() that does integer promotion
+ static_assert(std::is_same<A, decltype(+a)>::value, "a will not be promoted");
+ static_assert(std::is_same<B, decltype(+b)>::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<S>() :
+ // 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<S>::max() - a, b) ? std::optional<S>() :
+ std::optional<S>(a + b);
+}
+
+/// argument pack expansion termination for IncreaseSum<S, T, Args...>()
+template <typename S, typename T>
+std::optional<S>
+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<AllUnsigned>(s,t)
+ // but getting a _signed_ promoted value of s or t in s + t.
+ return IncreaseSumInternal<S>(+s, +t);
+}
+
+/// \returns a non-overflowing sum of the arguments (or nothing)
+template <typename S, typename T, typename... Args>
+std::optional<S>
+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<S>() triggers bogus -Wmaybe-uninitialized warnings in GCC v10.3
+ return std::nullopt;
+ }
+}
+
+/// \returns an exact, non-overflowing sum of the arguments (or nothing)
+template <typename SummationType, typename... Args>
+std::optional<SummationType>
+NaturalSum(const Args... args) {
+ return IncreaseSum<SummationType>(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 <typename S, typename... Args>
+S
+SetToNaturalSumOrMax(S &var, const Args... args)
+{
+ var = NaturalSum<S>(args...).value_or(std::numeric_limits<S>::max());
+ return var;
+}
+
+/// converts a given non-negative integer into an integer of a given type
+/// without loss of information or undefined behavior
+template <typename Result, typename Source>
+Result
+NaturalCast(const Source s)
+{
+ return NaturalSum<Result>(s).value();
+}
+
+#endif /* SQUID_SRC_SQUIDMATH_H */
--- a/src/http.cc
+++ b/src/http.cc
@@ -57,6 +57,7 @@
#include "StrList.h"
#include "tools.h"
#include "util.h"
+#include "SquidMath.h"
#if USE_AUTH
#include "auth/UserRequest.h"
@@ -1156,18 +1157,27 @@ HttpStateData::readReply(const CommIoCbP
* 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<size_t>(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<size_t>(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())
@@ -1522,8 +1532,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)
@@ -1541,40 +1553,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
+{
+ 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<size_t>(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<size_t>(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<size_t>
+HttpStateData::canBufferMoreReplyBytes() 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 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)
--- a/src/http.h
+++ b/src/http.h
@@ -15,6 +15,8 @@
#include "http/StateFlags.h"
#include "sbuf/SBuf.h"
+#include <optional>
+
class FwdState;
class HttpHeader;
@@ -107,16 +109,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<size_t> canBufferMoreReplyBytes() const;
+ size_t maybeMakeSpaceAvailable(size_t maxReadSize);
// consuming request body
virtual void handleMoreRequestBodyAvailable();

View File

@ -0,0 +1,138 @@
From 72a3bbd5e431597c3fdb56d752bc56b010ba3817 Mon Sep 17 00:00:00 2001
From: Alex Rousskov <rousskov@measurement-factory.com>
Date: Wed, 25 Oct 2023 11:47:19 +0000
Subject: [PATCH] Improve handling of expanding HTTP header values (#1536)
Squid manipulations often increase HTTP header value length compared to
the corresponding raw value received by Squid. Raw header length is
checked against request_header_max_size and reply_header_max_size that
default to 64KB, making the raw value safe to store in a String object
(by default). However, when the increased length of a manipulated value
exceeds String class limits, Squid leaks memory, asserts, or possibly
stalls affected transactions. The long-term fix for this problem is a
complete String elimination from Squid sources, but that takes time.
Known manipulations may effectively concatenate headers and/or increase
header value length by 50%. This workaround makes such known increases
safe by essentially tripling String class limits:
(64KB + 64KB) * 150% = 3 * 64KB
This bug was discovered and detailed by Joshua Rogers at
https://megamansec.github.io/Squid-Security-Audit/response-memleaks.html
where it was filed as "Memory Leak in HTTP Response Parsing".
Conflict: src/SquidString.h context adapt
Reference: https://github.com/squid-cache/squid/commit/72a3bbd5e431597c3fdb56d752bc56b010ba3817
---
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 21fdde598cb..ffb215fa5e7 100644
--- a/src/SquidString.h
+++ b/src/SquidString.h
@@ -140,7 +140,16 @@ class String
size_type len_; /* 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 6a0d253b139..e4a296005fd 100644
--- a/src/cache_cf.cc
+++ b/src/cache_cf.cc
@@ -1007,6 +1007,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 15e09c42378..986e31499a6 100644
--- a/src/cf.data.pre
+++ b/src/cf.data.pre
@@ -6753,11 +6753,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
@@ -6766,11 +6769,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 f4e96aacd52..138c845c7b0 100644
--- a/src/http.cc
+++ b/src/http.cc
@@ -1900,8 +1900,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?

View File

@ -0,0 +1,32 @@
From 920563e7a080155fae3ced73d6198781e8b0ff04 Mon Sep 17 00:00:00 2001
From: Francesco Chemolli <5175948+kinkie@users.noreply.github.com>
Date: Sun, 2 Jun 2024 14:41:16 +0000
Subject: [PATCH] Bug 5378: type mismatch in libTrie (#1830)
TrieNode::add() incorrectly computed an offset of an internal data
structure, resulting in out-of-bounds memory accesses that could cause
corruption or crashes.
This bug was discovered and detailed by Joshua Rogers at
https://megamansec.github.io/Squid-Security-Audit/esi-underflow.html
where it was filed as "Buffer Underflow in ESI".
Conflict: NA
Reference: https://github.com/squid-cache/squid/commit/920563e7a080155fae3ced73d6198781e8b0ff04
---
lib/libTrie/TrieNode.cc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/libTrie/TrieNode.cc b/lib/libTrie/TrieNode.cc
index 0f991a06d3e..d417e0f5448 100644
--- a/lib/libTrie/TrieNode.cc
+++ b/lib/libTrie/TrieNode.cc
@@ -32,7 +32,7 @@ TrieNode::add(char const *aString, size_t theLength, void *privatedata, TrieChar
/* We trust that privatedata and existant keys have already been checked */
if (theLength) {
- int index = transform ? (*transform)(*aString): *aString;
+ const unsigned char index = transform ? (*transform)(*aString): *aString;
if (!internal[index])
internal[index] = new TrieNode;

View File

@ -2,7 +2,7 @@
Name: squid
Version: 4.9
Release: 18
Release: 23
Summary: The Squid proxy caching server
Epoch: 7
License: GPLv2+ and (LGPLv2+ and MIT and BSD and Public Domain)
@ -52,6 +52,10 @@ Patch31:backport-CVE-2023-46728.patch
Patch32:backport-CVE-2023-49285.patch
Patch33:backport-CVE-2023-49286.patch
Patch34:backport-CVE-2023-50269.patch
Patch35:backport-CVE-2024-23638.patch
Patch36:backport-CVE-2024-25617.patch
Patch37:backport-CVE-2024-37894.patch
Patch38:backport-CVE-2024-25111.patch
Buildroot: %{_tmppath}/squid-4.9-1-root-%(%{__id_u} -n)
Requires: bash >= 2.0
@ -75,7 +79,7 @@ non-blocking, I/O-driven process and keeps meta data and implements negative cac
%build
autoreconf
automake
CXXFLAGS="$RPM_OPT_FLAGS -fPIC"
CXXFLAGS="$RPM_OPT_FLAGS -fPIC -std=c++17"
CFLAGS="$RPM_OPT_FLAGS -fPIC"
LDFLAGS="$RPM_LD_FLAGS -pie -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel"
@ -99,7 +103,7 @@ LDFLAGS="$RPM_LD_FLAGS -pie -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel"
--enable-linux-netfilter --enable-removal-policies="heap,lru" \
--enable-snmp --enable-ssl --enable-ssl-crtd \
--enable-storeio="aufs,diskd,ufs,rock" --enable-diskio --enable-wccpv2 \
--enable-esi --enable-ecap --with-aio --with-default-user="squid" \
--disable-esi --enable-ecap --with-aio --with-default-user="squid" \
--with-dl --with-openssl --with-pthreads --disable-arch-native \
--with-pic --disable-security-cert-validators \
--with-tdb
@ -237,6 +241,36 @@ fi
chgrp squid /var/cache/samba/winbindd_privileged >/dev/null 2>&1 || :
%changelog
* Tue Oct 29 2024 xinghe <xinghe2@h-partners.com> - 7:4.9-23
- Type:cves
- ID:CVE-2024-45802
- SUG:NA
- DESC:fix CVE-2024-45802
* Thu Sep 19 2024 xinghe <xinghe2@h-partners.com> - 7:4.9-22
- Type:cves
- ID:CVE-2024-25111
- SUG:NA
- DESC:fix CVE-2024-25111
* Wed Jun 26 2024 xinghe <xinghe2@h-partners.com> - 7:4.9-21
- Type:cves
- ID:CVE-2024-37894
- SUG:NA
- DESC:fix CVE-2024-37894
* Tue Feb 20 2024 xinghe <xinghe2@h-partners.com> - 7:4.9-20
- Type:cves
- ID:CVE-2024-25617
- SUG:NA
- DESC:fix CVE-2024-25617
* Thu Jan 25 2024 xinghe <xinghe2@h-partners.com> - 7:4.9-19
- Type:cves
- ID:CVE-2024-23638
- SUG:NA
- DESC:fix CVE-2024-23638
* Fri Dec 15 2023 xinghe <xinghe2@h-partners.com> - 7:4.9-18
- Type:cves
- ID:CVE-2023-50269