Skip to content
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

Fixed Heap-buffer-overflow in parse_unix via clusterfuzz #9833

Merged
merged 5 commits into from Feb 28, 2017

Conversation

@dgquintas
Copy link
Contributor Author

Do you know if something needs to be done to mark the clusterfuzz entry as fixed?


un->sun_family = AF_UNIX;
strcpy(un->sun_path, uri->path);
strncpy(un->sun_path, uri->path, sizeof(un->sun_path) - 1 /* null term'd */);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strncpy() is notoriously difficult to use in a safe way, because if the string is longer than the specified length, it does not copy the trailing NUL byte to the destination string. strlcpy() is a much safer alternative to strncpy(), but it's unfortunately not portable. :(

I assume that this misfeature of strncpy() is why you're using memset() above to initialize the whole struct. However, that seems a bit fragile, because a future developer looking at this code might think "the memset() isn't really necessary, because we're explicitly setting all of the fields below". An alternative would be to do something like this right after this line:

un->sun_path[sizeof(un->sun_path) - 1] = '\0';

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that was exactly why I was zeroing the memory. Good point though, setting the terminator explicitly is more robust.

Done.

@@ -51,7 +51,8 @@ int parse_unix(grpc_uri *uri, grpc_resolved_address *resolved_addr) {
struct sockaddr_un *un = (struct sockaddr_un *)resolved_addr->addr;

un->sun_family = AF_UNIX;
strcpy(un->sun_path, uri->path);
strncpy(un->sun_path, uri->path, sizeof(un->sun_path) - 1 /* null term'd */);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we just return 0 if uri->path is too long?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes. Done.

@@ -49,12 +49,11 @@

int parse_unix(grpc_uri *uri, grpc_resolved_address *resolved_addr) {
struct sockaddr_un *un = (struct sockaddr_un *)resolved_addr->addr;

const size_t maxlen = sizeof(un->sun_path);
if (strnlen(uri->path, maxlen) == maxlen) return 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't this fail if the size is exactly maxlen?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the size is exactly maxlen, we have a problem: the \0 would be one-past the end

resolved_addr->len = strlen(un->sun_path) + sizeof(un->sun_family) + 1;

strcpy(un->sun_path, uri->path);
resolved_addr->len = strlen(un->sun_path) + maxlen + 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you put maxlen here instead of sizeof(un->sun_family), where you probably actually meant to replace sizeof(un->sun_path).

Shouldn't this actually just be set to sizeof(struct sockaddr_un)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are too quick :) I noticed right after pushing, took me ~1 min to fix and re-push but that was already too late!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agh! hold on, push didn't go through...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, NOW. PTAL.

@dgquintas
Copy link
Contributor Author

dgquintas commented Feb 23, 2017 via email

resolved_addr->len = strlen(un->sun_path) + sizeof(un->sun_family) + 1;

strcpy(un->sun_path, uri->path);
resolved_addr->len = path_len + sizeof(un->sun_family) + 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't think it's appropriate to use path_len here, since the size of the address is the size of the buffer, not the size of the string in the buffer (which may be smaller than the full size of the buffer).

Why are we not simply saying resolved_addr->len = sizeof(struct sockaddr_un)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the previously existing logic, but I think you are right: all other types of addresses populate len with that way. Changed.

@@ -49,12 +49,12 @@

int parse_unix(grpc_uri *uri, grpc_resolved_address *resolved_addr) {
struct sockaddr_un *un = (struct sockaddr_un *)resolved_addr->addr;

const size_t maxlen = sizeof(un->sun_path);
const size_t path_len = strnlen(uri->path, maxlen);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't look like the logic actually changed here. But upon further review, I think this is correct: if the NUL byte is at maxlen, strnlen() will return maxlen - 1, which is fine, and if the NUL byte is at maxlen + 1, we don't have enough room in the buffer, so we should fail.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly.

@dgquintas
Copy link
Contributor Author

Issues: #9147 #9762 #9797 #9399

@dgquintas dgquintas merged commit 5f13f48 into grpc:master Feb 28, 2017
@lock lock bot locked as resolved and limited conversation to collaborators Jan 24, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants