Bug 5554: Cap absurd inherited RLIMIT_NOFILE - #2483
Conversation
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
7f6d150 to
3ad247b
Compare
This comment was marked as resolved.
This comment was marked as resolved.
3ad247b to
c041695
Compare
| return result; | ||
| } | ||
| #endif // _SQUID_WINDOWS_ || _SQUID_MINGW_ | ||
|
|
There was a problem hiding this comment.
Please restore the empty line at the end of the file.
Apart from this, looks good to me!
There was a problem hiding this comment.
Please restore the empty line at the end of the file.
I will fix this while working on the adjustments mentioned in another change request.
rousskov
left a comment
There was a problem hiding this comment.
Bug report: Squid should not blindly trust an absurd inherited soft limit and allocate unbounded descriptor tables before startup completes. It should cap an inherited default to a safe compiled/runtime limit, or otherwise reject it with a clear diagnostic.
Thank you for this bug report and analysis, Max! I agree with the above conclusion and support this PR direction. Some PR changes are required, but I will implement them myself in hope to reduce the number of review iterations and cumulative time spent on this PR. Please stand by -- the ball is in my court.
Since this is your first Squid contribution, I will also add your entry to the CONTRIBUTORS file (unless you stop me).
| // ulimit trigger multi-gigabyte allocations (e.g. Kubernetes may | ||
| // provide a billion-descriptor soft limit). This guard runs before | ||
| // fde::Init() and Comm callback tables allocate descriptor storage. | ||
| if (Config.max_filedescriptors <= 0 && |
There was a problem hiding this comment.
This new code deals with so called "inherited" limit, but it is placed into the existing else clause where a non-inherited limit is also tested, necessitating unwanted Config.max_filedescriptors check duplication. The existing code is already messy, but it is easy to avoid making it worse AFAICT.
I will try to adjust this code to avoid this problem. It is easier to do that than to describe that adjustment.
| // provide a billion-descriptor soft limit). This guard runs before | ||
| // fde::Init() and Comm callback tables allocate descriptor storage. | ||
| if (Config.max_filedescriptors <= 0 && | ||
| rl.rlim_cur > static_cast<rlim_t>(SQUID_MAXFD)) { |
There was a problem hiding this comment.
I assume Squid supports exceeding SQUID_MAXFD -- existing Config.max_filedescriptors code above does not check SQUID_MAXFD.
I fear that this new check will break many existing legitimate descriptor increases via "inherited ulimit" because SQUID_MAXFD is going to be too small in those cases. There is nothing about "absurd" (using PR title terminology) in this proposed PR code. The proposed C++ comment says "unexpectedly large", but if overwriting SQUID_MAXFD via ulimit is supported, then we cannot claim that all reasonable ulimit values are "unexpected".
While working on the adjustments mentioned in another change request, I plan to add what this PR title promises -- detection of absurdly large inherited RLIMIT_NOFILE value.
| debugs(50, DBG_IMPORTANT, "WARNING: inherited RLIMIT_NOFILE (" << | ||
| rl.rlim_cur << ") exceeds Squid's compiled descriptor limit (" << | ||
| SQUID_MAXFD << "); limiting to " << SQUID_MAXFD); | ||
| rl.rlim_cur = SQUID_MAXFD; |
There was a problem hiding this comment.
We should not overwrite rl, especially if we do not call setrlimit() with the new/overwritten value. We should set Squid_MaxFD directly instead.
While working on the adjustments mentioned in another change request, I will address this concern.
| return result; | ||
| } | ||
| #endif // _SQUID_WINDOWS_ || _SQUID_MINGW_ | ||
|
|
There was a problem hiding this comment.
Please restore the empty line at the end of the file.
I will fix this while working on the adjustments mentioned in another change request.
|
Thanks @rousskov for taking over - highly appreciate your time you put into this project - really big fan of squid and using it in one of my side projects. |
Bug 5554: Squid can allocate huge memory from RLIMIT_NOFILE
Bug report: https://bugs.squid-cache.org/show_bug.cgi?id=5554
When Squid starts in a Kubernetes/containerd environment, it may inherit
an absurdly large RLIMIT_NOFILE soft limit (for example 1073741816).
Squid currently uses that value as Squid_MaxFD and eagerly allocates
several descriptor-sized tables during startup. The result is
approximately 536-568 GiB of virtual memory, high CPU, and an
OOM/unusable process before it can serve requests.
The same behavior reproduces with current Squid master (8.0.0-VCS) in an
empty Kubernetes pod. The packaged Squid 7.6 image reproduces it as
well. Outside Kubernetes, with a normal descriptor limit, the same image
starts normally.
Relevant allocation path:
This patch caps an inherited default above SQUID_MAXFD before those
allocations and emits a warning. Explicit max_filedescriptors
configuration remains honored, including values above SQUID_MAXFD where
supported.
Before:
RLIMIT_NOFILE=1073741816
VmSize approximately 562-595 GB
pod becomes unusable/OOMs
After:
warning reports the inherited limit and the 32768 cap
VmSize approximately 38 MB
VmRSS approximately 20 MB
pod remains Running
An explicit max_filedescriptors 1048576 regression check remains
honored.
Testing:
in the same pod.