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