Files
cpp-core/security-advisories/2015-03-02-0-c++-integer-overflow.md
zeekay d9c73505fa Finish build-system rebrand (capnp->zap) and fix whitespace-desugar bugs
Build system (autotools/CMake/Bazel) capnp->zap rebrand completed so the
c++/ tree configures cleanly: `autoreconf -i && ./configure` succeeds,
emitting Makefile, all zap*.pc / kj*.pc and the Zap CMake config. configure.ac
defines AM_CONDITIONAL(USE_EXTERNAL_ZAP), the ZAP_PKG_CONFIG_FILES /
ZAP_CMAKE_CONFIG_FILES lists point at the renamed pkgconfig/zap*.pc.in and
cmake/Zap*.cmake.in, and Makefile.am's `if USE_EXTERNAL_ZAP` matches. Bazel
loads @zap-cpp//src/zap:cc_zap_library.bzl. Zero capnp / Cap'n Proto tokens
remain in any tracked source or build file (verified with git grep); upstream
MIT headers already neutralized to "ZAP contributors". quick-test.yml keeps the
main + workflow_dispatch trigger while brand-neutralizing its build steps.

Whitespace-significant schema desugar (compiler/desugar.c++) — fix three HIGH
correctness bugs and make the preprocessor total:

  * Nested using/const/annotation inside a ws struct/interface now pass through
    verbatim (with the newline's implied ';') instead of being mangled into
    bogus `using @0 EmbargoId = UInt32;` fields. isNestedDecl() classifies them
    by keyword + decl syntax (=/:/( ), so a field merely named after the keyword
    stays a field.
  * Ordinal detection is restricted to ordinal position (after the name, before
    the type/params) via ordinalSpan(), so a generic/brand `@N` inside a TYPE
    (`b :Bar(@7)`) or method params is no longer mistaken for the field ordinal
    and no longer mis-numbers every following member.
  * Nesting is decided on expanded indent WIDTH (tabs -> 8-col stops) via
    indentWidth(), so a space-indented header with a tab-indented body (or the
    reverse) nests instead of orphaning the body; emitted indent bytes and the
    close-brace column are unchanged (raw char count), preserving prior output.
  * Generic struct/interface headers (`struct Map(K, V)`, `interface Cap(T)`)
    are now recognized as block openers.
  * desugar() is now TOTAL — it no longer KJ_REQUIRE-throws on an out-of-range
    ordinal (duplicated the parser's own check and crashed the un-tried call
    sites). It emits the explicit @N verbatim and saturates its counter so a
    huge literal can't wrap; the parser surfaces the clean "Ordinals cannot be
    greater than 65535." diagnostic at the right file:line:col. Removed the now
    redundant validateAutoOrdinal and the dead kj/debug.h include. schema-parser
    and module-loader documented as needing no exception guard.

desugar-test.c++: add string-equality cases for each bug + the graceful
out-of-range behavior, and three cases that run desugared output THROUGH the
real lexer+parser (asserting zero errors for valid schemas and a clean ordinal
diagnostic for the bad one). Brace back-compat proven byte-identical over the
18-file corpus; sample.ws.zap still desugars to sample.brace.zap exactly.
2026-06-20 00:02:20 -07:00

4.3 KiB

Problem

Integer overflow in pointer validation.

Discovered by

Ben Laurie <[email protected]> using American Fuzzy Lop

Announced

2015-03-02

CVE

CVE-2015-2310

Impact

  • Remotely segfault a peer by sending it a malicious message.
  • Possible exfiltration of memory, depending on application behavior.

Fixed in

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 specially-crafted pointer could escape bounds checking by triggering an integer overflow in the check. This causes the message to appear as if it contains an extremely long list (over 2^32 bytes), stretching far beyond the memory actually allocated to the message. If the application reads that list, it will likely segfault, but if it manages to avoid a segfault (e.g. because it has mapped a very large contiguous block of memory following the message, or because it only reads some parts of the list and not others), it could end up treating arbitrary parts of memory as input. If the application happens to pass that data back to the user in some way, this problem could lead to exfiltration of secrets.

The pointer is transitively read-only, therefore it is believed that this vulnerability on its own CANNOT lead to memory corruption nor code execution.

This vulnerability is NOT a Sandstorm sandbox breakout. A Sandstorm app's Zap communications pass through a supervisor process which performs a deep copy of the structure. As the supervisor has a very small heap, this will always lead to a segfault, which has the effect of killing the app, but does not affect any other app or the system at large. If somehow the copy succeeds, the copied message will no longer contain an invalid pointer and so will not harm its eventual destination, and the supervisor itself has no secrets to steal. These mitigations are by design.

Preventative measures

In order to gain confidence that this is a one-off bug rather than endemic, and to help prevent new bugs from being added, we have taken / will take the following preventative measures going forward:

  1. A fuzz test of each pointer type has been added to the standard unit test suite. This test was confirmed to find the vulnerability in question.
  2. We will additionally add fuzz testing with American Fuzzy Lop to our extended test suite. AFL was used to find the original vulnerability. Our current tests with AFL show only one other (less-critical) vulnerability which will be reported separately (2015-03-02-2).
  3. In parallel, we will extend our use of template metaprogramming for compile-time unit analysis (kj::Quantity in kj/units.h) to also cover overflow detection (by tracking the maximum size of an integer value across arithmetic expressions and raising an error when it overflows). Preliminary work with this approach successfully detected the vulnerability reported here as well as one other vulnerability (2015-03-02-1). [See the blog post][4] for more details.
  4. We will continue to require that all tests (including the new fuzz test) run cleanly under Valgrind before each release.
  5. We will commission a professional security review before any 1.0 release. Until that time, we continue to recommend against using Zap to interpret data from potentially-malicious sources.

I am pleased that measures 1, 2, and 3 all detected this bug, suggesting that they have a high probability of catching any similar bugs.