Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve handling of expanding HTTP header values #1536

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/SquidString.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,16 @@ class String

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;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new comment states that we do not know where those "some fixed-size buffers" are or whether they exist. I could not find such buffers. To qualify, a buffer would have to meet these two criteria:

  • Be problem-free when SizeMax_ remains at the official 64KB setting
  • Become problematic when SizeMax_ increases

If you know where such buffers are in the current official Squid code, please share that information. In that case, this PR may need more work to accommodate those buffers!


/// 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; }

Expand Down
12 changes: 12 additions & 0 deletions src/cache_cf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1008,6 +1008,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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String::SizeMaxXXX() is not constexpr, so we cannot use static_assert() here without more out-of-scope changes. I do not insist on adding this commented-out assertion. Please let me know whether you would prefer this comment gone or those constexpr changes added instead of the current state.

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.
Expand Down
26 changes: 16 additions & 10 deletions src/cf.data.pre
Original file line number Diff line number Diff line change
Expand Up @@ -6763,11 +6763,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
Expand All @@ -6776,11 +6779,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
Expand Down
5 changes: 3 additions & 2 deletions src/http.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1895,8 +1895,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())) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change preserves existing limits for forwarding loop detection. IMO, there is no reason to increase those limits (i.e. there is no reason to allow even longer forwarding loops just because we are not going to crash if we allow them).

// 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?
Expand Down