Skip to content

Reject excessively large FTP control replies#2434

Closed
somecookie wants to merge 24 commits into
squid-cache:masterfrom
measurement-factory:OSD-9-handling-of-large-ftp-tokens
Closed

Reject excessively large FTP control replies#2434
somecookie wants to merge 24 commits into
squid-cache:masterfrom
measurement-factory:OSD-9-handling-of-large-ftp-tokens

Conversation

@somecookie
Copy link
Copy Markdown
Contributor

@somecookie somecookie commented Jun 4, 2026

When parsing FTP control replies, Ftp::Client::parseControlReply()
stores individual lines in the ctrl.message wordlist. The stored
values are later combined, appended, encoded, and/or converted to String
objects, exposing the results to String::SizeMax_ limitations. Recent
commit 46f3f80 already ensures reply_header_max_size limits for
control replies. This change adds checks for cases where
reply_header_max_size configuration exceeds the recommended maximum
value. It also protects any sensitive worldlist-manipulating code that
might become reachable before reply_header_max_size limit is checked.

Excessively large FTP control replies now lead to ERR_FTP_FAILURE.

This is a Measurement Factory project.

somecookie and others added 24 commits May 26, 2026 10:33
... and renamed SafeRawTokenSizeMax() to RawSizeMaxXXX().

When checking String limits in new/adjusted code X, we are trying to
protect legacy code Y _that runs later/elsewhere_ and that does not
check SizeMaxXXX(). We add a check to X, but it is meant for Y.

We have two basic concerns about Y:

* Y may concatenate our raw tokens. We can easily prevent such "pure"
  accumulation from exceeding the limit by checking SizeMaxXXX() in X.
  If accumulation were the only concern, our new code would just check
  SizeMaxXXX(). There would be no need for `SizeMaxXXX()+1)/3` hacks!

* Y may grow/encode our raw input. We can prevent known algorithms from
  exceeding the limit by accounting for code Y growth factor in code X.
  For example, if Y concatenates raw tokens while separating them with a
  space character, then such an algorithm can double raw input size (at
  the most). If Y applies URI percent-encoding, it can triple raw input
  size. This is where our `SizeMaxXXX()+1)/3` hacks become handy.

Since SizeMaxXXX() exceeds RawSizeMaxXXX(), checking the latter is
enough.

The renaming part of this change also preserves XXX in every caller that
is using the formerly unnamed `SizeMaxXXX()+1)/3` hack (which had an XXX
in it). We want to continue to mark such callers as problematic...
Overriding increases diff noise, touches legacy code that we want to
remove, and makes it impossible to use wordlistDestroy name as an
std::unique_ptr template type parameter (because there are two functions
with that name), resulting in more complex and odd/asymmetric
std::unique_ptr construction compared to the nearby sbufOwner
construction.

An acceptable alternative would be to add worldlistFree() or a similar
function that does not override wordlistDestroy().

The problem stems from the unfortunate existing "safe" wordlistDestroy()
API that does not use a "safe" word in its name. We cannot fix that
preexisting problem without make a lot of out-of-scope changes.
This change also helps avoid using rather odd "char[]" type for the
first std::unique_ptr parameter. sbufOwner now allocates and deletes
"void*" memory, while `sbuf` uses a c-string "view" of that memory.
Our "token len" could incorrectly imply that we are measuring the length
of a single (growing) token.
@squid-anubis squid-anubis added the M-failed-description https://github.com/measurement-factory/anubis#pull-request-labels label Jun 4, 2026
@squid-anubis

This comment was marked as resolved.

@squid-anubis squid-anubis removed the M-failed-description https://github.com/measurement-factory/anubis#pull-request-labels label Jun 4, 2026
Copy link
Copy Markdown
Contributor

@rousskov rousskov left a comment

Choose a reason for hiding this comment

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

Thank you for tightening up this code!

N.B. This PR completes the work started in 46f3f80. There is one more FTP-related fix in the pipeline.

Comment thread src/clients/FtpClient.cc
Comment on lines 1175 to +1176
linelen = strcspn(s, crlf) + 1;
replyLength += linelen;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I believe this "total" length calculation math protects Squid from raw input expansion due to a combination of percent-encoding and existing wordlist items concatenation code. These kind of protections are rather weak, of course, but that is why we have already added a warning for the admins about increasing reply_header_max_size and why the corresponding limit functions have XXX in their names. This old problem will go away with the last String instance.

This comment does not request any changes.

@rousskov rousskov added M-cleared-for-merge https://github.com/measurement-factory/anubis#pull-request-labels S-could-use-an-approval An approval may speed this PR merger (but is not required) labels Jun 4, 2026
Copy link
Copy Markdown
Contributor

@yadij yadij left a comment

Choose a reason for hiding this comment

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

Good enough.

@yadij yadij removed the S-could-use-an-approval An approval may speed this PR merger (but is not required) label Jun 7, 2026
squid-anubis pushed a commit that referenced this pull request Jun 7, 2026
When parsing FTP control replies, `Ftp::Client::parseControlReply()`
stores individual lines in the `ctrl.message` wordlist. The stored
values are later combined, appended, encoded, and/or converted to String
objects, exposing the results to `String::SizeMax_` limitations. Recent
commit 46f3f80 already ensures `reply_header_max_size` limits for
control replies. This change adds checks for cases where
`reply_header_max_size` configuration exceeds the recommended maximum
value. It also protects any sensitive worldlist-manipulating code that
might become reachable before `reply_header_max_size` limit is checked.

Excessively large FTP control replies now lead to ERR_FTP_FAILURE.

This is a Measurement Factory project.
@squid-anubis squid-anubis added M-waiting-staging-checks https://github.com/measurement-factory/anubis#pull-request-labels M-failed-staging-checks https://github.com/measurement-factory/anubis#pull-request-labels and removed M-waiting-staging-checks https://github.com/measurement-factory/anubis#pull-request-labels labels Jun 7, 2026
@rousskov rousskov removed the M-failed-staging-checks https://github.com/measurement-factory/anubis#pull-request-labels label Jun 7, 2026
@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 Jun 7, 2026
@yadij yadij added the backport-to-v7 maintainer has approved these changes for v7 backporting label Jun 7, 2026
@squidadm squidadm removed the backport-to-v7 maintainer has approved these changes for v7 backporting label Jun 7, 2026
@squidadm
Copy link
Copy Markdown
Collaborator

squidadm commented Jun 7, 2026

queued for backport to v7

kinkie pushed a commit that referenced this pull request Jun 7, 2026
When parsing FTP control replies, `Ftp::Client::parseControlReply()`
stores individual lines in the `ctrl.message` wordlist. The stored
values are later combined, appended, encoded, and/or converted to String
objects, exposing the results to `String::SizeMax_` limitations. Recent
commit 46f3f80 already ensures `reply_header_max_size` limits for
control replies. This change adds checks for cases where
`reply_header_max_size` configuration exceeds the recommended maximum
value. It also protects any sensitive worldlist-manipulating code that
might become reachable before `reply_header_max_size` limit is checked.

Excessively large FTP control replies now lead to ERR_FTP_FAILURE.

This is a Measurement Factory project.

---------

Co-authored-by: Ricardo Ferreira Ribeiro <garb12@pm.me>
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

Development

Successfully merging this pull request may close these issues.

5 participants