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

Conversation

rousskov
Copy link
Contributor

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".

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".
// 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.

/// 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!

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).

@kinkie
Copy link
Contributor

kinkie commented Oct 24, 2023

The approach looks like a sensible patch; has it been tested in any way?

@rousskov
Copy link
Contributor Author

rousskov commented Oct 24, 2023

The approach looks like a sensible patch; has it been tested in any way?

Yes, of course. All PRs are supposed to be tested unless noted otherwise. Factory PRs, including this one, follow that rule.

Needless to say, it is not feasible to test all code paths affected by this change in the maximum String buffer size. Besides testing, I did try to find all limit users, and analyzed the ones I found.

We plan to add the corresponding CI regression tests, but fixing other Zero Day vulnerabilities with published reproducers takes priority.

@yadij yadij added M-cleared-for-merge https://github.com/measurement-factory/anubis#pull-request-labels backport-to-v5 maintainer has approved these changes for v5 backporting backport-to-v6 maintainer has approved these changes for v6 backporting labels Oct 24, 2023
@squid-anubis squid-anubis added the M-waiting-staging-checks https://github.com/measurement-factory/anubis#pull-request-labels label Oct 25, 2023
squid-anubis pushed a commit that referenced this pull request Oct 25, 2023
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".
@squid-anubis squid-anubis added M-merged https://github.com/measurement-factory/anubis#pull-request-labels and removed M-waiting-staging-checks https://github.com/measurement-factory/anubis#pull-request-labels M-cleared-for-merge https://github.com/measurement-factory/anubis#pull-request-labels labels Oct 25, 2023
squidadm pushed a commit to squidadm/squid that referenced this pull request Oct 26, 2023
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".
@squidadm squidadm removed the backport-to-v6 maintainer has approved these changes for v6 backporting label Oct 26, 2023
@squidadm
Copy link
Collaborator

queued for backport to v6

yadij pushed a commit that referenced this pull request Oct 27, 2023
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".
squidadm pushed a commit to squidadm/squid that referenced this pull request Oct 27, 2023
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".
yadij pushed a commit that referenced this pull request Oct 28, 2023
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".
@yadij yadij removed the backport-to-v5 maintainer has approved these changes for v5 backporting label Nov 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
M-merged https://github.com/measurement-factory/anubis#pull-request-labels
Projects
None yet
5 participants