Reject excessively long dst, src, and localip ACL parameters - #2478
Reject excessively long dst, src, and localip ACL parameters#2478k-furman wants to merge 2 commits into
Conversation
This comment was marked as resolved.
This comment was marked as resolved.
rousskov
left a comment
There was a problem hiding this comment.
Thank you for posting this PR. It needs a few corrections, but nothing major AFAICT. Please let me know if you want me to do any of the suggested changes.
Please check the adjusted PR title/description. They will become a commit message when this PR is merged. I edited them to focus the title on admin-visible effects and to avoid retelling what the diff clearly says. I also wanted to clarify the scope of the proposed trailing garbage checks.
Finally, please add the author line from the first PR branch commit (or, if needed, an alternative entry) to CONTRIBUTORS. Our CI tests will check for that automatically. If you do not want any such entry, please let me know, and we will take care of that manually.
This change fixes buffer overflows when acl_ip_data::FactoryParse() is given malformed dst, src, and localip ACL configuration parameters with values exceeding 255 characters. Squid now also detects (and rejects) trailing parameter garbage in more cases. FactoryParse() sscanf() calls were writing raw input into 256-byte buffers without checking input size. This change adds these limits: - IPv6 input patterns: 39 bytes per address and 3 bytes for the mask. - IPv4 input patterns: 15 bytes per address and 15 bytes for the mask. - Non-IP input patterns: 255 per address and 255 for the mask. We now also extend trailing garbage checks to all of the above patterns.
15309af to
c72b844
Compare
|
Many thanks for detailed answer! I fixed all things you suggested, squash commits, change commit message and head as in PR, and force-pushed it. Also, I add a line with my name in CONTRIBUTORS, as you tell. |
| #define SCAN_ACL1_6 "%39[0123456789ABCDEFabcdef:]-%39[0123456789ABCDEFabcdef:]/%3[0123456789]%c" | ||
| #define SCAN_ACL2_6 "%39[0123456789ABCDEFabcdef:]-%39[0123456789ABCDEFabcdef:]%c" | ||
| #define SCAN_ACL3_6 "%39[0123456789ABCDEFabcdef:]/%3[0123456789]%c" | ||
| #define SCAN_ACL4_6 "%39[0123456789ABCDEFabcdef:]/%c" |
There was a problem hiding this comment.
SCAN_ACL4_6 pattern and, hence, the code that uses SCAN_ACL4_6 seem to miss an overflow check. However, the root of the problem lies much deeper and creates more/other bugs. It took me a while to sort through this mess. @k-furman, this is not your fault -- your PR simply exposed more old bugs than we thought it did. I detailed my findings further below.
At this point, we need to make a decision:
-
Do our best to ignore the newly discovered bugs in the official parsing code. Reduce this PR scope to preventing known buffer overflows. Remove "reject trailing garbage" bonus changes because they cannot be done right until other parsing bugs are fixed. AFAICT, this implies undoing
%cadditions and relatedsscanf()calls/conditions changes in this PR. -
Fix all known parsing bugs, including, but not limited to, buffer overflows and failures to reject trailing garbage.
@k-furman, which option do you prefer? I will update this PR review and/or code based on your preference.
After examining the history of this code, I now know that trailing %c in the official IPv4 patterns were added to correctly handle cases like 123.example.com and 123-456.example.com (see year-2000 commits 20a4484 and 588b63e). Those cases are quite similar to the "trailing garbage" handling that this PR is trying to fix, but that trailing input is a part of a valid domain name in those cases... AFAICT, when adding IPv6 support, 2007 commit cc192b5 then misinterpreted and broke that tricky code by replacing the corresponding correct (but strange-looking) IPv4 conditions/pattern and propagating those buggy replacements to IPv6 code:
-#define SCAN_ACL4 "%[0123456789.]%c"
+#define SCAN_ACL4_4 "%[0123456789.]/%c" // wrong pattern change
...
- } else if (sscanf(t, SCAN_ACL2, addr1, addr2, &c) == 2) {
+ } else if (sscanf(t, SCAN_ACL2_4, addr1, addr2, &c) >= 2) { // wrong condition change
...
- } else if (sscanf(t, SCAN_ACL4, addr1, &c) == 1) {
+ } else if (sscanf(t, SCAN_ACL4_4, addr1,&c) == 2) { // wrong condition change+#define SCAN_ACL4_6 "%[0123456789ABCDEFabcdef:]/%c" // broken IPv4 pattern copied to IPv6 code
...
+ } else if (sscanf(t, SCAN_ACL2_6, addr1, addr2, &c) >= 2) { // broken IPv4 condition copied to IPv6 code
...
+ } else if (sscanf(t, SCAN_ACL4_6, addr1, mask) == 2) { // broken IPv4 condition copied to IPv6 code and the wrong parameter used for storing %cSince that 2007 commit cc192b5, Squid misinterprets various ACL configurations, rejecting valid input like dead-beef.example.test. We are also silently accepting buggy input like 192.0.2.1/XXX4, which is arguably even worse:
2026/08/24 14:03:21| ERROR: aclIpParseIpData: unknown first address in 'dead-beef.example.test'
2026/08/24 11:10:53.840| 28,9| Ip.cc(272) FactoryParse: aclIpParseIpData: '192.0.2.1/XXX4' matched: SCAN4-v4: %[0123456789.]/%c
2026/08/24 11:10:53.840| 28,9| Ip.cc(416) FactoryParse: Parsed: 192.0.2.1-[::]/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff](/128)
This change fixes buffer overflows when
acl_ip_data::FactoryParse()isgiven malformed
dst,src, andlocalipACL configuration parameterswith values exceeding 255 characters. Squid now also detects (and
rejects) trailing parameter garbage in more cases.
FactoryParse()sscanf()calls were writing raw input into 256-bytebuffers without checking input size. This change adds these limits:
We now also extend trailing garbage checks to all of the above patterns.