-
Notifications
You must be signed in to change notification settings - Fork 37.7k
fuzz: avoid returning non-conforming results from FuzzedSock::GetSockName() #32109
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
base: master
Are you sure you want to change the base?
Conversation
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code Coverage & BenchmarksFor details see: https://corecheck.dev/bitcoin/bitcoin/pulls/32109. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. |
…Name() It would be a bug in `getsockname(2)` if it returns a result that is smaller than the returned socket address family. For example, if it indicates that the result is less than `sizeof(sockaddr_in6)` and sets `sa_family` equal to `AF_INET6` in the output. In other words, the `name->sa_family` in the output should be consistent with the returned `*name_len`. The current code could fail to do that if: * the caller provides `sockaddr_in6` and an input value of `*name_len=28` * `ConsumeRandomLengthByteVector()` returns a vector of `20` bytes. Then the code would only set the first `20` bytes in `name`. * `name->sa_family` from the fuzz data ends up being `AF_INET6`. To produce consistent `*name_len` and `name->sa_family`, return one of `AF_INET`, `AF_INET6` or `AF_UNIX` for family with the corresponding `*name_len`. For reference: ``` sizeof(sockaddr) = 16 sizeof(sockaddr_in) = 16 sizeof(sockaddr_in6) = 28 sizeof(sockaddr_un) = 110 on Linux, 106 on FreeBSD (unix socket) sizeof(sockaddr_storage) = 128 ``` https://www.man7.org/linux/man-pages/man3/sockaddr.3type.html
cc @darosior, @marcofleon |
🚧 At least one of the CI tasks failed. HintsTry to run the tests locally, according to the documentation. However, a CI failure may still
Leave a comment here, if you need help tracking down a confusing failure. |
9c3298e
to
52b6518
Compare
|
Concept ACK
FWIW, i've tried to make our code robust to this case by adding the length checks in ab1d3ec. But it's a very unlikely OS bug and this change will likely result in more useful test coverage. |
Leaning toward Concept NACK. OP is suggesting to provide more guarantees in our mocked In addition i think that trying to give the guarantees that OP suggests will lead to unnecessarily convoluted code in the fuzz utility.
Maybe. But it also does not give any such guarantee, so code assuming this is brittle.
(Second quote is from #31676 (comment)) Code that, when reading the socket addr buffer, disregards said buffer size and blindly relies on the socket family type is brittle and should be fixed. |
Yes. Though to be fair, it's something hard to get right due to lack of guarantees with regard to the socket name structure on different platforms. For example, even reading How much effort to spend on this depends on how far you want to go down this rabbit hole of "the OS could give us malicious data". |
It is ok to assume the OS functions conform to their specifications and our production code need not handle non-conforming behavior from OS functions. For example, Do you agree? From here it follows that the mocked/fuzzed OS functions must be conforming as well. E.g. if we mock Right? Now, I guess, the question here is whether int socket = ...;
sockaddr_in name_in;
socklen_t len = sizeof(name_in);
sockaddr* name = (sockaddr*)&name_in;
if (getsockname(socket, name, &len) == 0) {
if (name.sa_family == AF_INET && len == 3) {
// Is this getsockname() conforming? Or is that a bug in
// getsockname() that our production code should not care about,
// like memcpy() not copying the bytes, or fopen() not setting errno?
}
} |
It would be a bug in
getsockname(2)
if it returns a result that is smaller than the returned socket address family. For example, if it indicates that the result is less thansizeof(sockaddr_in6)
and setssa_family
equal toAF_INET6
in the output.In other words, the
name->sa_family
in the output should be consistent with the returned*name_len
.The current code could fail to do that if:
sockaddr_in6
and an input value of*name_len=28
ConsumeRandomLengthByteVector()
returns a vector of20
bytes. Then the code would only set the first20
bytes inname
.name->sa_family
from the fuzz data ends up beingAF_INET6
.To produce consistent
*name_len
andname->sa_family
, return one ofAF_INET
,AF_INET6
orAF_UNIX
for family with the corresponding*name_len
.For reference:
https://www.man7.org/linux/man-pages/man3/sockaddr.3type.html