annotate src/capnproto-git-20161025/doc/_posts/2015-03-02-security-advisory-and-integer-overflow-protection.md @ 133:1ac99bfc383d

Add Cap'n Proto source
author Chris Cannam <cannam@all-day-breakfast.com>
date Tue, 25 Oct 2016 11:17:01 +0100
parents
children
rev   line source
cannam@133 1 ---
cannam@133 2 layout: post
cannam@133 3 title: "Security Advisory -- And how to catch integer overflows with template metaprogramming"
cannam@133 4 author: kentonv
cannam@133 5 ---
cannam@133 6
cannam@133 7 As the installation page has always stated, I do not yet recommend using Cap'n Proto's C++ library for handling possibly-malicious input, and will not recommend it until it undergoes a formal security review. That said, security is obviously a high priority for the project. The security of Cap'n Proto is in fact essential to the security of [Sandstorm.io](https://sandstorm.io), Cap'n Proto's parent project, in which sandboxed apps communicate with each other and the platform via Cap'n Proto RPC.
cannam@133 8
cannam@133 9 A few days ago, the first major security bugs were found in Cap'n Proto C++ -- two by security guru [Ben Laurie](http://en.wikipedia.org/wiki/Ben_Laurie) and one by myself during subsequent review (see below). You can read details about each bug in our new [security advisories directory](https://github.com/sandstorm-io/capnproto/tree/master/security-advisories):
cannam@133 10
cannam@133 11 * [Integer overflow in pointer validation.](https://github.com/sandstorm-io/capnproto/tree/master/security-advisories/2015-03-02-0-c++-integer-overflow.md)
cannam@133 12 * [Integer underflow in pointer validation.](https://github.com/sandstorm-io/capnproto/tree/master/security-advisories/2015-03-02-1-c++-integer-underflow.md)
cannam@133 13 * [CPU usage amplification attack.](https://github.com/sandstorm-io/capnproto/tree/master/security-advisories/2015-03-02-2-all-cpu-amplification.md)
cannam@133 14
cannam@133 15 I have backported the fixes to the last two release branches -- 0.5 and 0.4:
cannam@133 16
cannam@133 17 - Release 0.5.1.1: [source](https://capnproto.org/capnproto-c++-0.5.1.1.tar.gz), [win32](https://capnproto.org/capnproto-c++-win32-0.5.1.1.zip)
cannam@133 18 - Release 0.4.1.1: [source](https://capnproto.org/capnproto-c++-0.4.1.1.tar.gz)
cannam@133 19
cannam@133 20 Note that we added a "nano" component to the version number (rather than use 0.5.2/0.4.2) to indicate that this release is ABI-compatible with the previous release. If you are linking Cap'n Proto as a shared library, you only need to update the library, not re-compile your app.
cannam@133 21
cannam@133 22 To be clear, the first two bugs affect only the C++ implementation of Cap'n Proto; implementations in other languages are likely safe. The third bug probably affects all languages, and as of this writing only the C++ implementation (and wrappers around it) is fixed. However, this third bug is not as serious as the other two.
cannam@133 23
cannam@133 24 ### Preventative Measures
cannam@133 25
cannam@133 26 It is our policy that any time a security problem is found, we will not only fix the problem, but also implement new measures to prevent the class of problems from occurring again. To that end, here's what we're doing doing to avoid problems like these in the future:
cannam@133 27
cannam@133 28 1. A fuzz test of each pointer type has been added to the standard unit test
cannam@133 29 suite.
cannam@133 30 2. We will additionally add fuzz testing with American Fuzzy Lop to our
cannam@133 31 extended test suite.
cannam@133 32 3. In parallel, we will extend our use of template metaprogramming for
cannam@133 33 compile-time unit analysis (kj::Quantity in kj/units.h) to also cover
cannam@133 34 overflow detection (by tracking the maximum size of an integer value across
cannam@133 35 arithmetic expressions and raising an error when it overflows). More on this
cannam@133 36 below.
cannam@133 37 4. We will continue to require that all tests (including the new fuzz test) run
cannam@133 38 cleanly under Valgrind before each release.
cannam@133 39 5. We will commission a professional security review before any 1.0 release.
cannam@133 40 Until that time, we continue to recommend against using Cap'n Proto to
cannam@133 41 interpret data from potentially-malicious sources.
cannam@133 42
cannam@133 43 I am pleased to report that measures 1, 2, and 3 all detected both integer overflow/underflow problems, and AFL additionally detected the CPU amplification problem.
cannam@133 44
cannam@133 45 ### Integer Overflow is Hard
cannam@133 46
cannam@133 47 Integer overflow is a nasty problem.
cannam@133 48
cannam@133 49 In the past, C and C++ code has been plagued by buffer overrun bugs, but these days, systems engineers have mostly learned to avoid them by simply never using static-sized buffers for dynamically-sized content. If we don't see proof that a buffer is the size of the content we're putting in it, our "spidey sense" kicks in.
cannam@133 50
cannam@133 51 But developing a similar sense for integer overflow is hard. We do arithmetic in code all the time, and the vast majority of it isn't an issue. The few places where overflow can happen all too easily go unnoticed.
cannam@133 52
cannam@133 53 And by the way, integer overflow affects many memory-safe languages too! Java and C# don't protect against overflow. Python does, using slow arbitrary-precision integers. Javascript doesn't use integers, and is instead succeptible to loss-of-precision bugs, which can have similar (but more subtle) consequences.
cannam@133 54
cannam@133 55 While writing Cap'n Proto, I made sure to think carefully about overflow and managed to correct for it most of the time. On learning that I missed a case, I immediately feared that I might have missed many more, and wondered how I might go about systematically finding them.
cannam@133 56
cannam@133 57 Fuzz testing -- e.g. using [American Fuzzy Lop](http://lcamtuf.coredump.cx/afl/) -- is one approach, and is indeed how Ben found the two bugs he reported. As mentioned above, we will make AFL part of our release process in the future. However, AFL cannot really _prove_ anything -- it can only try lots of possibilities. I want my compiler to refuse to compile arithmetic which might overflow.
cannam@133 58
cannam@133 59 ### Proving Safety Through Template Metaprogramming
cannam@133 60
cannam@133 61 C++ Template Metaprogramming is powerful -- many would say _too_ powerful. As it turns out, it's powerful enough to do what we want.
cannam@133 62
cannam@133 63 I defined a new type:
cannam@133 64
cannam@133 65 {% highlight C++ %}
cannam@133 66 template <uint64_t maxN, typename T>
cannam@133 67 class Guarded {
cannam@133 68 // Wraps T (a basic integer type) and statically guarantees
cannam@133 69 // that the value can be no more than `maxN` and no less than
cannam@133 70 // zero.
cannam@133 71
cannam@133 72 static_assert(maxN <= T(kj::maxValue), "possible overflow detected");
cannam@133 73 // If maxN is not representable in type T, we can no longer
cannam@133 74 // guarantee no overflows.
cannam@133 75
cannam@133 76 public:
cannam@133 77 // ...
cannam@133 78
cannam@133 79 template <uint64_t otherMax, typename OtherT>
cannam@133 80 inline constexpr Guarded(const Guarded<otherMax, OtherT>& other)
cannam@133 81 : value(other.value) {
cannam@133 82 // You cannot construct a Guarded from another Guarded
cannam@133 83 // with a higher maximum.
cannam@133 84 static_assert(otherMax <= maxN, "possible overflow detected");
cannam@133 85 }
cannam@133 86
cannam@133 87 // ...
cannam@133 88
cannam@133 89 template <uint64_t otherMax, typename otherT>
cannam@133 90 inline constexpr Guarded<guardedAdd<maxN, otherMax>(),
cannam@133 91 decltype(T() + otherT())>
cannam@133 92 operator+(const Guarded<otherMax, otherT>& other) const {
cannam@133 93 // Addition operator also computes the new maximum.
cannam@133 94 // (`guardedAdd` is a constexpr template that adds two
cannam@133 95 // constants while detecting overflow.)
cannam@133 96 return Guarded<guardedAdd<maxN, otherMax>(),
cannam@133 97 decltype(T() + otherT())>(
cannam@133 98 value + other.value, unsafe);
cannam@133 99 }
cannam@133 100
cannam@133 101 // ...
cannam@133 102
cannam@133 103 private:
cannam@133 104 T value;
cannam@133 105 };
cannam@133 106 {% endhighlight %}
cannam@133 107
cannam@133 108 So, a `Guarded<10, int>` represents a `int` which is statically guaranteed to hold a non-negative value no greater than 10. If you add a `Guarded<10, int>` to `Guarded<15, int>`, the result is a `Guarded<25, int>`. If you try to initialize a `Guarded<10, int>` from a `Guarded<25, int>`, you'll trigger a `static_assert` -- the compiler will complain. You can, however, initialize a `Guarded<25, int>` from a `Guarded<10, int>` with no problem.
cannam@133 109
cannam@133 110 Moreover, because all of `Guarded`'s operators are inline and `constexpr`, a good optimizing compiler will be able to optimize `Guarded` down to the underlying primitive integer type. So, in theory, using `Guarded` has no runtime overhead. (I have not yet verified that real compilers get this right, but I suspect they do.)
cannam@133 111
cannam@133 112 Of course, the full implementation is considerably more complicated than this. The code has not been merged into the Cap'n Proto tree yet as we need to do more analysis to make sure it has no negative impact. For now, you can find it in the [overflow-safe](https://github.com/sandstorm-io/capnproto/tree/overflow-safe) branch, specifically in the second half of [kj/units.h](https://github.com/sandstorm-io/capnproto/blob/overflow-safe/c++/src/kj/units.h). (This header also contains metaprogramming for compile-time unit analysis, which Cap'n Proto has been using since its first release.)
cannam@133 113
cannam@133 114 ### Results
cannam@133 115
cannam@133 116 I switched Cap'n Proto's core pointer validation code (`capnp/layout.c++`) over to `Guarded`. In the process, I found:
cannam@133 117
cannam@133 118 * Several overflows that could be triggered by the application calling methods with invalid parameters, but not by a remote attacker providing invalid message data. We will change the code to check these in the future, but they are not critical security problems.
cannam@133 119 * The overflow that Ben had already reported ([2015-03-02-0](https://github.com/sandstorm-io/capnproto/tree/master/security-advisories/2015-03-02-0-c++-integer-overflow.md)). I had intentionally left this unfixed during my analysis to verify that `Guarded` would catch it.
cannam@133 120 * One otherwise-undiscovered integer underflow ([2015-03-02-1](https://github.com/sandstorm-io/capnproto/tree/master/security-advisories/2015-03-02-1-c++-integer-underflow.md)).
cannam@133 121
cannam@133 122 Based on these results, I conclude that `Guarded` is in fact effective at finding overflow bugs, and that such bugs are thankfully _not_ endemic in Cap'n Proto's code.
cannam@133 123
cannam@133 124 With that said, it does not seem practical to change every integer throughout the Cap'n Proto codebase to use `Guarded` -- using it in the API would create too much confusion and cognitive overhead for users, and would force application code to be more verbose. Therefore, this approach unfortunately will not be able to find all integer overflows throughout the entire library, but fortunately the most sensitive parts are covered in `layout.c++`.
cannam@133 125
cannam@133 126 ### Why don't programming languages do this?
cannam@133 127
cannam@133 128 Anything that can be implemented in C++ templates can obviously be implemented by the compiler directly. So, why have so many languages settled for either modular arithmetic or slow arbitrary-precision integers?
cannam@133 129
cannam@133 130 Languages could even do something which my templates cannot: allow me to declare relations between variables. For example, I would like to be able to declare an integer whose value is less than the size of some array. Then I know that the integer is a safe index for the array, without any run-time check.
cannam@133 131
cannam@133 132 Obviously, I'm not the first to think of this. "Dependent types" have been researched for decades, but we have yet to see a practical language supporting them. Apparently, something about them is complicated, even though the rules look like they should be simple enough from where I'm standing.
cannam@133 133
cannam@133 134 Some day, I would like to design a language that gets this right. But for the moment, I remain focused on [Sandstorm.io](https://sandstorm.io). Hopefully someone will beat me to it. Hint hint.