-
Notifications
You must be signed in to change notification settings - Fork 610
ICP: Fix validation of packet sizes and URLs #2220
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
Changes from all commits
75da7f1
9af3d82
6ba936c
d7ad9f6
59fad26
f1dd43d
b2545d7
5124ca8
233382a
99ac265
628970f
75bc759
0f4ce08
3f293b3
84e1473
5bf7c21
c00b0b5
34df9b4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -425,7 +425,7 @@ icpCreateAndSend(icp_opcode opcode, int flags, char const *url, int reqnum, int | |
| } | ||
|
|
||
| void | ||
| icpDenyAccess(Ip::Address &from, char *url, int reqnum, int fd) | ||
| icpDenyAccess(const Ip::Address &from, const char * const url, const int reqnum, const int fd) | ||
| { | ||
| if (clientdbCutoffDenied(from)) { | ||
| /* | ||
|
|
@@ -457,11 +457,43 @@ icpAccessAllowed(Ip::Address &from, HttpRequest * icp_request) | |
| return false; | ||
| } | ||
|
|
||
| const char * | ||
| icpGetUrl(const Ip::Address &from, const char * const buf, const icp_common_t &header) | ||
| { | ||
| const auto receivedPacketSize = static_cast<size_t>(header.length); | ||
| const auto payloadOffset = sizeof(header); | ||
|
|
||
| // Query payload contains a "Requester Host Address" followed by a URL. | ||
| // Payload of other ICP packets (with opcode that we recognize) is a URL. | ||
| const auto urlOffset = payloadOffset + ((header.opcode == ICP_QUERY) ? sizeof(uint32_t) : 0); | ||
|
|
||
| // A URL field cannot be empty because it includes a terminating NUL char. | ||
| // Ensure that the packet has at least one URL field byte. | ||
| if (urlOffset >= receivedPacketSize) { | ||
| debugs(12, 3, "too small packet from " << from << ": " << urlOffset << " >= " << receivedPacketSize); | ||
| return nullptr; | ||
| } | ||
|
|
||
| // All ICP packets (with opcode that we recognize) _end_ with a URL field. | ||
| // RFC 2186 requires all URLs to be "Null-Terminated". | ||
| if (buf[receivedPacketSize - 1] != '\0') { | ||
| debugs(12, 3, "unterminated URL or trailing garbage from " << from); | ||
| return nullptr; | ||
| } | ||
|
|
||
| const auto url = buf + urlOffset; // a possibly empty c-string | ||
| if (urlOffset + strlen(url) + 1 != receivedPacketSize) { | ||
| debugs(12, 3, "URL with an embedded NUL or trailing garbage from " << from); | ||
| return nullptr; | ||
| } | ||
|
|
||
| return url; | ||
| } | ||
|
|
||
| HttpRequest * | ||
| icpGetRequest(char *url, int reqnum, int fd, Ip::Address &from) | ||
| icpGetRequest(const char * const url, const int reqnum, const int fd, const Ip::Address &from) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I improved const-correctness of |
||
| { | ||
| if (strpbrk(url, w_space)) { | ||
| url = rfc1738_escape(url); | ||
| icpCreateAndSend(ICP_ERR, 0, rfc1738_escape(url), reqnum, 0, fd, from, nullptr); | ||
| return nullptr; | ||
| } | ||
|
|
@@ -476,13 +508,18 @@ icpGetRequest(char *url, int reqnum, int fd, Ip::Address &from) | |
| } | ||
|
|
||
| static void | ||
| doV2Query(int fd, Ip::Address &from, char *buf, icp_common_t header) | ||
| doV2Query(const int fd, Ip::Address &from, const char * const buf, icp_common_t header) | ||
| { | ||
| int rtt = 0; | ||
| int src_rtt = 0; | ||
| uint32_t flags = 0; | ||
| /* We have a valid packet */ | ||
rousskov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| char *url = buf + sizeof(icp_common_t) + sizeof(uint32_t); | ||
rousskov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| const auto url = icpGetUrl(from, buf, header); | ||
| if (!url) { | ||
| icpCreateAndSend(ICP_ERR, 0, "", header.reqnum, 0, fd, from, nullptr); | ||
| return; | ||
| } | ||
|
|
||
| HttpRequest *icp_request = icpGetRequest(url, header.reqnum, fd, from); | ||
|
|
||
| if (!icp_request) | ||
|
|
@@ -549,7 +586,9 @@ icp_common_t::handleReply(char *buf, Ip::Address &from) | |
| neighbors_do_private_keys = 0; | ||
| } | ||
|
|
||
| char *url = buf + sizeof(icp_common_t); | ||
| const auto url = icpGetUrl(from, buf, *this); | ||
| if (!url) | ||
| return; | ||
| debugs(12, 3, "icpHandleIcpV2: " << icp_opcode_str[opcode] << " from " << from << " for '" << url << "'"); | ||
|
|
||
| const cache_key *key = icpGetCacheKey(url, (int) reqnum); | ||
|
|
@@ -661,7 +700,10 @@ icpHandleUdp(int sock, void *) | |
|
|
||
| icp_version = (int) buf[1]; /* cheat! */ | ||
|
|
||
| if (icpOutgoingConn->local == from) | ||
| // XXX: The IP equality comparison below ignores port differences but | ||
| // should not. It also fails to detect loops when `local` is a wildcard | ||
| // address (e.g., [::]:3130) because `from` address is never a wildcard. | ||
| if (icpOutgoingConn && icpOutgoingConn->local == from) | ||
| // ignore ICP packets which loop back (multicast usually) | ||
| debugs(12, 4, "icpHandleUdp: Ignoring UDP packet sent by myself"); | ||
| else if (icp_version == ICP_VERSION_2) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is one of the cases where we should be using the constructor-conversion to have the compiler do the right thing without risking memory bytes outside the
shorttype being used by the largersize_tvalue.I do not insist on this change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are no such risks: No compiler is going to look beyond integer
xwhen compilingstatic_cast<T>(x). And if we consider hypothetical cases wherexis no longer an integer, then using an explicit type conversion does not protect the compiler from looking beyond the intended bytes either!In general, static_casts are overall better than explicit type conversion, even when functional notation (a.k.a. function-style cast) is used for the latter:
The only disadvantage of a
static_castis that it takes 13 more characters to type.Rule of thumb: When possible, use static_cast to cast.
Thank you.