-
-
Notifications
You must be signed in to change notification settings - Fork 6.6k
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
vtls: fix potential version string overflow #3863
vtls: fix potential version string overflow #3863
Conversation
lib/vtls/vtls.c
Outdated
@@ -1243,7 +1243,7 @@ static size_t Curl_multissl_version(char *buffer, size_t size) | |||
|
|||
selected = current; | |||
|
|||
for(i = 0; available_backends[i]; i++) { | |||
for(i = 0; available_backends[i] && p < backends + sizeof(backends); i++) { |
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.
You'll have to account for each time p is incremented. How about
if(current != selected) {
char *p = backends;
char *end = backends + sizeof(backends);
int i;
selected = current;
for(i = 0; available_backends[i] && p < end - 4; i++) {
if(i)
*(p++) = ' ';
if(selected != available_backends[i])
*(p++) = '(';
p += available_backends[i]->version(p, end - p - 2);
if(selected != available_backends[i])
*(p++) = ')';
}
*p = '\0';
total = p - backends;
}
Also I suggest increase it to like 1k size, 200 seems low for multiple versions.
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.
also what is supposed to happen here if(current==selected)?
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.
If we need to increase the backends
buffer, or perhaps independently of that, we should also increase the version
and the ssl_version
buffers that are used to get this output (in lib/version.c) - both of them are probably in the smaller end if someone builds a curl with all possible TLS backends enabled (not sure exactly how many and which that might be).
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.
also what is supposed to happen here if(current==selected)?
It's keeping the buffer cached in case the current TLS backend hasn't changed between calls, as the selectdt backend is printed differently from the rest.
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.
You'll have to account for each time p is incremented.
Good catch, fixing.
Also I suggest increase it to like 1k size, 200 seems low for multiple versions.
I'm not sure 200 characters is too low, and 1k seems like excessive stack usage, but there are definitely buffers in the version printing which needs to get bumped. That's will be a separate PR though.
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 would imagine 200 should be enough. If you manage to build with 6 backends, that makes it 33 bytes per backend, and I don't think any backend uses that much. 8 backends give 25 bytes each, probably also plenty enough.
I doubt we can build with more than 8, if even that...
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.
Good catch, fixing.
I've added p += available_backends[i]->version(p, end - p - 2);
since it wasn't in the fix. Technically if bytes written returned is always going to be less than the count passed (eg version(foo, 5) and therefore the max it will return is 4 bec it accounts for the null) you only need to subtract 1 but I think subtracting 2 makes the intention clearer.
lib/vtls/vtls.c
Outdated
memcpy(buffer, backends, total + 1); | ||
else { | ||
memcpy(buffer, backends, size - 1); | ||
buffer[size - 1] = '\0'; | ||
} | ||
|
||
return total; | ||
return CURLMIN(size, total); |
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.
size - 1
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.
Ah, yes.
In Curl_multissl_version() it was possible to overflow the passed in buffer if the generated version string exceeded the size of the buffer. Fix by inverting the logic, and also make sure to not exceed the local buffer during the string generation. Closes #xxxx Reported-by: nevv on HackerOne/curl
8bbfa52
to
629f4c6
Compare
Pushed a rebased fixup version with the comments addressed. |
When running a multi TLS backend build the version string needs more buffer space. Make the internal ssl_buffer stack buffer match the one in Curl_multissl_version() to allow for the longer string. For single TLS backend builds there is no use in extended to buffer. This is a fallout from curl#3863 which fixes up the multi_ssl string generation to avoid a buffer overflow when the buffer is too small.
Squashed and pushed this to master, thanks for review! |
When running a multi TLS backend build the version string needs more buffer space. Make the internal ssl_buffer stack buffer match the one in Curl_multissl_version() to allow for the longer string. For single TLS backend builds there is no use in extended to buffer. This is a fallout from #3863 which fixes up the multi_ssl string generation to avoid a buffer overflow when the buffer is too small. Closes #3875 Reviewed-by: Daniel Stenberg <daniel@haxx.se>
if(i) | ||
*(p++) = ' '; | ||
if(selected != available_backends[i]) | ||
*(p++) = '('; | ||
p += available_backends[i]->version(p, backends + sizeof(backends) - p); | ||
p += available_backends[i]->version(p, end - p - 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.
Shouldn't this be an end - p > 2 ? end - p - 2 : 0
? The second parameter is declared as size_t
, i.e. unsigned...
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.
end - p is always > 2 at that point, refer to the loop condition p < (end - 4)
, then after that p
can be incremented twice before end - p - 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.
Right, unless I'm missing something @jay is right, the current coding should be safe (but it might warrant a comment explaining it).
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 find adding a comment to be unnecessary I think it's pretty straightforward.
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.
Well, one could just write the loop condition as ...&& (end - p) > 4
and it'd be easier to read
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 find adding a comment to be unnecessary I think it's pretty straightforward.
So you're saying that I am dumb. Because I did not see that.
I don't take this personally, coming from you, as I had pleasant and productive interactions with you in the past, but I wonder whether you realized how unfortunate a reaction your comment would elicit (and I think it is pretty obvious that it would do exactly that). Might want to be more careful.
In short: while it might be obvious to you, now, I think that my comment is testament enough to give evidence to the contrary. And who knows, maybe you yourself will belong into the same "wait, what?" camp in 6 months from now.
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 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 find adding a comment to be unnecessary I think it's pretty straightforward.
So you're saying that I am dumb. Because I did not see that.
I don't take this personally, coming from you, as I had pleasant and productive interactions with you in the past, but I wonder whether you realized how unfortunate a reaction your comment would elicit (and I think it is pretty obvious that it would do exactly that). Might want to be more careful.
In short: while it might be obvious to you, now, I think that my comment is testament enough to give evidence to the contrary. And who knows, maybe you yourself will belong into the same "wait, what?" camp in 6 months from now.
Whoa I may not be very tactful but don't put words in my mouth. I figured you misread the code, like I do occasionally. I would've shared my opinion even if that wasn't the case. If you had a different opinion that's all you needed to say in your reply.
Anyway, clearly my opinion of it being straightforward is not in favor. Someone propose a comment so we can put this to bed. /* end - p is > 2 at this point */
?
In
Curl_multissl_version()
it was possible to overflow the passed in buffer if the generated version string exceeded the size of the buffer. Fix by inverting the logic, and also make sure to not exceed the local buffer during the string generation.Reported-by: nevv on HackerOne/curl