Skip to content

buffer: fix vulnerabilities when allocation fails#5468

Merged
ggreenway merged 2 commits intoenvoyproxy:masterfrom
ggreenway:fix-oom-handling
Jan 3, 2019
Merged

buffer: fix vulnerabilities when allocation fails#5468
ggreenway merged 2 commits intoenvoyproxy:masterfrom
ggreenway:fix-oom-handling

Conversation

@ggreenway
Copy link
Member

If allocations in Buffer::OwnedImpl fail in reserve(), the caller may write to uninitialized pointers. There are various callers that would fall into this path, and it may be possible to develop an exploit based on this.

A similar allocation failure could occur in linearize(), which could result in a NULL-pointer dereference. Because this is undefined-behavior in C++, this should be avoided. This could also result in reading/writing to arbitrary memory (NULL + offset) if either offset is large (and thus points to a valid virtual memory address), or very low addresses are mapped in the process.

Typically on linux, allocations do not fail, and OOM conditions are resolved by the kernel killing a process to reclaim memory. However, with various ulimit and cgroup options, an allocation could return NULL.

Signed-off-by: Greg Greenway ggreenway@apple.com

Risk Level: Low
Testing: Existing tests pass, but no additional testing was added because there isn't an easy way to make libevent allocations fail in tests, and this code is currently being rewritten (see #5441).
Docs Changes: None
Release Notes: TODO

If allocations in Buffer::OwnedImpl fail in reserve(), the
caller may write to uninitialized pointers. There are various
callers that would fall into this path, and it may be possible
to develop an exploit based on this.

A similar allocation failure could occur in linearize(), which
could result in a NULL-pointer dereference. Because this is
undefined-behavior in C++, this should be avoided. This
could also result in reading/writing to arbitrary memory
(NULL + offset) if either offset is large (and thus points
to a valid virtual memory address), or very low addresses
are mapped in the process.

Typically on linux, allocations do not fail, and OOM conditions
are resolved by the kernel killing a process to reclaim memory.
However, with various ulimit and cgroup options, an allocation
could return NULL.

Signed-off-by: Greg Greenway <ggreenway@apple.com>
Signed-off-by: Greg Greenway <ggreenway@apple.com>
@ggreenway
Copy link
Member Author

ggreenway commented Jan 3, 2019

Related: should we be calling std::set_new_handler (http://www.cplusplus.com/reference/new/set_new_handler/) with a function that calls PANIC() or abort() so that we get consistent results if a std::bad_alloc would have been thrown? Right now, the result will depend on which thread it occurs in, and whether there is a try {} block around it or not.

Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

Thanks. re: a new handler, we don't blindly catch std::exception anywhere, so it should be OK and cause a crash, but it can't hurt so seems like a good idea. Open a tracking issue or just do a PR?

ASSERT(size <= length());
return evbuffer_pullup(buffer_.get(), size);
void* const ret = evbuffer_pullup(buffer_.get(), size);
RELEASE_ASSERT(ret != nullptr || size == 0,
Copy link
Member

Choose a reason for hiding this comment

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

Do we want to fail on size == 0 here? I don't feel strongly but it seems like they should be OK?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is explicitly not failing if size == 0 because this case occurs in the tests. And I don't think we should crash when you have something that evaluates to:

void* foo = buf.linearize(0);
for (int i = 0; i < 0; i++) {
   x = foo[i];
}

Copy link
Member

Choose a reason for hiding this comment

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

Sorry, I read this as the reverse that it would crash when size == 0. Yes this makes sense.

@mattklein123 mattklein123 self-assigned this Jan 3, 2019
@ggreenway
Copy link
Member Author

/retest

@ggreenway ggreenway merged commit e556672 into envoyproxy:master Jan 3, 2019
fredlas pushed a commit to fredlas/envoy that referenced this pull request Mar 5, 2019
* buffer: fix vulnerabilities when allocation fails

If allocations in Buffer::OwnedImpl fail in reserve(), the
caller may write to uninitialized pointers. There are various
callers that would fall into this path, and it may be possible
to develop an exploit based on this.

A similar allocation failure could occur in linearize(), which
could result in a NULL-pointer dereference. Because this is
undefined-behavior in C++, this should be avoided. This
could also result in reading/writing to arbitrary memory
(NULL + offset) if either offset is large (and thus points
to a valid virtual memory address), or very low addresses
are mapped in the process.

Typically on linux, allocations do not fail, and OOM conditions
are resolved by the kernel killing a process to reclaim memory.
However, with various ulimit and cgroup options, an allocation
could return NULL.

Signed-off-by: Greg Greenway <ggreenway@apple.com>
Signed-off-by: Fred Douglas <fredlas@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants