111 lines
4.5 KiB
Markdown
111 lines
4.5 KiB
Markdown
|
Problem
|
||
|
=======
|
||
|
|
||
|
Integer underflow in pointer validation.
|
||
|
|
||
|
Discovered by
|
||
|
=============
|
||
|
|
||
|
Kenton Varda <kenton@sandstorm.io>
|
||
|
|
||
|
Announced
|
||
|
=========
|
||
|
|
||
|
2015-03-02
|
||
|
|
||
|
CVE
|
||
|
===
|
||
|
|
||
|
CVE-2015-2311
|
||
|
|
||
|
Impact
|
||
|
======
|
||
|
|
||
|
- Remotely segfault a peer by sending it a malicious message.
|
||
|
- Possible exfiltration of memory, depending on application behavior.
|
||
|
- If the application performs a sequence of operations that "probably" no
|
||
|
application does (see below), possible memory corruption / code execution.
|
||
|
|
||
|
Fixed in
|
||
|
========
|
||
|
|
||
|
- git commit [26bcceda72372211063d62aab7e45665faa83633][0]
|
||
|
- release 0.5.1.1:
|
||
|
- Unix: https://capnproto.org/capnproto-c++-0.5.1.1.tar.gz
|
||
|
- Windows: https://capnproto.org/capnproto-c++-win32-0.5.1.1.zip
|
||
|
- release 0.4.1.1:
|
||
|
- Unix: https://capnproto.org/capnproto-c++-0.4.1.1.tar.gz
|
||
|
- release 0.6 (future)
|
||
|
|
||
|
[0]: https://github.com/sandstorm-io/capnproto/commit/26bcceda72372211063d62aab7e45665faa83633
|
||
|
|
||
|
Details
|
||
|
=======
|
||
|
|
||
|
*The following text contains speculation about the exploitability of this
|
||
|
bug. This is provided for informational purposes, but as such speculation is
|
||
|
often shown to be wrong, you should not rely on the accuracy of this
|
||
|
section for the safety of your service. Please update your library.*
|
||
|
|
||
|
A `Text` pointer, when non-null, must point to a NUL-terminated string, meaning
|
||
|
it must have a size of at least 1. Under most circumstances, Cap'n Proto will
|
||
|
reject zero-size text objects. However, if an application performs the
|
||
|
following sequence, they may hit a code path that was missing a check:
|
||
|
|
||
|
1. Receive a message containing a `Text` value, but do not actually look at
|
||
|
that value.
|
||
|
2. Copy the message into a `MessageBuilder`.
|
||
|
3. Call the `get()` method for the `Text` value within the `MessageBuilder`,
|
||
|
obtaining a `Text::Builder` for the *copy*.
|
||
|
|
||
|
In this case, the `Text::Builder` will appear to point at a string with size
|
||
|
2^32-1, starting at a location within the Cap'n Proto message.
|
||
|
|
||
|
The `Text::Builder` is writable. If the application decided to overwrite the
|
||
|
text in-place, it could overwrite arbitrary memory in the next 4GB of virtual
|
||
|
address space. However, there are several reasons to believe this is unusual:
|
||
|
|
||
|
- Usually, when an application `get()`s a text field, it only intends to
|
||
|
read it. Overwriting the text in-place is unusual.
|
||
|
- Calling `set()` on the field -- the usual way to overwrite text -- will
|
||
|
create an all-new text object and harmlessly discard the old, invalid
|
||
|
pointer.
|
||
|
|
||
|
Note that even if an application does overwrite the text, it would still be
|
||
|
hard for the attacker to exploit this for code execution unless the attacker
|
||
|
also controls the data that the application writes into the field.
|
||
|
|
||
|
This vulnerability is somewhat more likely to allow exfiltration of memory.
|
||
|
However, this requires the app to additionally echo the text back to the
|
||
|
attacker. To do this without segfaulting, the app would either need to attempt
|
||
|
to read only a subset of the text, or would need to have 2^32 contiguous bytes
|
||
|
of virtual memory mapped into its address space.
|
||
|
|
||
|
A related problem, also fixed in this change, occurs when a `Text` value
|
||
|
has non-zero size but lacks a NUL terminator. Again, if an application
|
||
|
performs the series of operations described above, the NUL terminator check
|
||
|
may be bypassed. If the app then passes the string to an API that assumes
|
||
|
NUL-terminated strings, the contents of memory after the text blob may be
|
||
|
interpreted as being part of the string, up to the next zero-valued byte.
|
||
|
This again could lead to exfiltration of data, this time without the high
|
||
|
chance of segfault, although only up to the next zero-valued byte, which
|
||
|
are typically quite common.
|
||
|
|
||
|
Preventative measures
|
||
|
=====================
|
||
|
|
||
|
This problem was discovered through preventative measures implemented after
|
||
|
the security problem discussed in the [previous advisory][1]. Specifically, this
|
||
|
problem was found by using template metaprogramming to implement integer
|
||
|
bounds analysis in order to effectively "prove" that there are no integer
|
||
|
overflows in the core pointer validation code (capnp/layout.c++).
|
||
|
Tentatively, I believe that this analysis exhaustively covers this file.
|
||
|
The instrumentation has not been merged into master yet as it requires some
|
||
|
cleanup, but [check the Cap'n Proto blog for an in-depth discussion][2].
|
||
|
|
||
|
This problem is also caught by capnp/fuzz-test.c++, which *has* been
|
||
|
merged into master but likely doesn't have as broad coverage.
|
||
|
|
||
|
[1]: https://github.com/sandstorm-io/capnproto/tree/master/security-advisories/2015-03-02-0-c++-integer-overflow.md
|
||
|
[2]: https://capnproto.org/news/2015-03-02-security-advisory-and-integer-overflow-protection.html
|