diff -Nru capnproto-0.4.0/debian/changelog capnproto-0.4.0/debian/changelog --- capnproto-0.4.0/debian/changelog 2014-04-01 11:31:58.000000000 +0000 +++ capnproto-0.4.0/debian/changelog 2018-07-30 23:00:29.000000000 +0000 @@ -1,3 +1,29 @@ +capnproto (0.4.0-1ubuntu2.1) trusty-security; urgency=medium + + * SECURITY UPDATE: Integer overflow in pointer validation. + - debian/patches/CVE-2015-2310.patch: fix in src/capnp/layout.c++ + - CVE-2015-2310 + + * SECURITY UPDATE: Integer underflow in pointer validation. + - debian/patches/CVE-2015-2311.patch: fix in src/capnp/layout.c++ + - CVE-2015-2311 + + * SECURITY UPDATE: CPU usage amplification attack. + - debian/patches/CVE-2015-2312.patch: fix in src/capnp/arena.h, + src/capnp/encoding-test.c++ and src/capnp/layout.c++ + - CVE-2015-2312 + + * SECURITY UPDATE: CPU additional CPU amplification case. + - debian/patches/CVE-2015-2313.patch: fix in src/capnp/layout.c++ + and src/capnp/encoding-test.c++ + - CVE-2015-2313 + + * SECURITY UPDATE: Prevent compiler from eliding bounds checks. + - debian/patches/CVE-2017-7892.patch: fix in src/capnp/arena.h + - CVE-2017-7892 + + -- Eduardo Barretto Mon, 30 Jul 2018 20:00:10 -0300 + capnproto (0.4.0-1ubuntu2) trusty; urgency=medium * Bump compat level to 9. diff -Nru capnproto-0.4.0/debian/patches/CVE-2015-2310.patch capnproto-0.4.0/debian/patches/CVE-2015-2310.patch --- capnproto-0.4.0/debian/patches/CVE-2015-2310.patch 1970-01-01 00:00:00.000000000 +0000 +++ capnproto-0.4.0/debian/patches/CVE-2015-2310.patch 2018-07-27 19:46:20.000000000 +0000 @@ -0,0 +1,42 @@ +From c0441ece9bb018ff05711c0ec0b9f5ceb25ca114 Mon Sep 17 00:00:00 2001 +From: Kenton Varda +Date: Wed, 25 Feb 2015 13:50:43 -0800 +Subject: [PATCH] SECURITY: Integer overflow in pointer validation. + +Details: https://github.com/sandstorm-io/capnproto/tree/master/security-advisories/2014-03-02-0-c++-integer-overflow.md +--- + src/capnp/layout.c++ | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/src/capnp/layout.c++ b/src/capnp/layout.c++ +index f25278093..7c7f566f0 100644 +--- a/src/capnp/layout.c++ ++++ b/src/capnp/layout.c++ +@@ -662,7 +662,8 @@ struct WireHelpers { + return result; + } + +- KJ_REQUIRE(elementTag->structRef.wordSize() / ELEMENTS * count <= wordCount, ++ KJ_REQUIRE(elementTag->structRef.wordSize() / ELEMENTS * ++ ElementCount64(count) <= wordCount, + "Struct list pointer's elements overran size.") { + return result; + } +@@ -1681,7 +1682,7 @@ struct WireHelpers { + ElementCount elementCount = tag->inlineCompositeListElementCount(); + auto wordsPerElement = tag->structRef.wordSize() / ELEMENTS; + +- KJ_REQUIRE(wordsPerElement * elementCount <= wordCount, ++ KJ_REQUIRE(wordsPerElement * ElementCount64(elementCount) <= wordCount, + "INLINE_COMPOSITE list's elements overrun its word count.") { + goto useDefault; + } +@@ -1923,7 +1924,7 @@ struct WireHelpers { + size = tag->inlineCompositeListElementCount(); + wordsPerElement = tag->structRef.wordSize() / ELEMENTS; + +- KJ_REQUIRE(size * wordsPerElement <= wordCount, ++ KJ_REQUIRE(ElementCount64(size) * wordsPerElement <= wordCount, + "INLINE_COMPOSITE list's elements overrun its word count.") { + goto useDefault; + } diff -Nru capnproto-0.4.0/debian/patches/CVE-2015-2311.patch capnproto-0.4.0/debian/patches/CVE-2015-2311.patch --- capnproto-0.4.0/debian/patches/CVE-2015-2311.patch 1970-01-01 00:00:00.000000000 +0000 +++ capnproto-0.4.0/debian/patches/CVE-2015-2311.patch 2018-07-30 15:54:28.000000000 +0000 @@ -0,0 +1,44 @@ +From e84ae6e395ba6e6e8616bd3d40f7a7d50ad5b5ed Mon Sep 17 00:00:00 2001 +From: Kenton Varda +Date: Fri, 27 Feb 2015 19:53:07 -0800 +Subject: [PATCH] SECURITY: Integer underflow in pointer validation. + +Details: https://github.com/sandstorm-io/capnproto/tree/master/security-advisories/2014-03-02-1-c++-integer-underflow.md +--- + src/capnp/layout.c++ | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/src/capnp/layout.c++ b/src/capnp/layout.c++ +index 7c7f566f0..b0c09b7a5 100644 +--- a/src/capnp/layout.c++ ++++ b/src/capnp/layout.c++ +@@ -1437,6 +1437,7 @@ struct WireHelpers { + WirePointer* ref, word* refTarget, SegmentBuilder* segment, + const void* defaultValue, ByteCount defaultSize)) { + if (ref->isNull()) { ++ useDefault: + if (defaultSize == 0 * BYTES) { + return nullptr; + } else { +@@ -1446,14 +1447,19 @@ struct WireHelpers { + } + } else { + word* ptr = followFars(ref, refTarget, segment); ++ char* cptr = reinterpret_cast(ptr); + + KJ_REQUIRE(ref->kind() == WirePointer::LIST, + "Called getText{Field,Element}() but existing pointer is not a list."); + KJ_REQUIRE(ref->listRef.elementSize() == FieldSize::BYTE, + "Called getText{Field,Element}() but existing list pointer is not byte-sized."); + +- // Subtract 1 from the size for the NUL terminator. +- return Text::Builder(reinterpret_cast(ptr), ref->listRef.elementCount() / ELEMENTS - 1); ++ size_t size = ref->listRef.elementCount() / ELEMENTS; ++ KJ_REQUIRE(size > 0 && cptr[size-1] == '\0', "Text blob missing NUL terminator.") { ++ goto useDefault; ++ } ++ ++ return Text::Builder(cptr, size - 1); + } + } + diff -Nru capnproto-0.4.0/debian/patches/CVE-2015-2312.patch capnproto-0.4.0/debian/patches/CVE-2015-2312.patch --- capnproto-0.4.0/debian/patches/CVE-2015-2312.patch 1970-01-01 00:00:00.000000000 +0000 +++ capnproto-0.4.0/debian/patches/CVE-2015-2312.patch 2018-07-30 16:26:56.000000000 +0000 @@ -0,0 +1,192 @@ +From 4caa02ed303689323cda603928fe6a09a6d9fa74 Mon Sep 17 00:00:00 2001 +From: Kenton Varda +Date: Fri, 27 Feb 2015 20:23:13 -0800 +Subject: [PATCH] SECURITY: CPU usage amplification attack. + +Details: https://github.com/sandstorm-io/capnproto/tree/master/security-advisories/2014-03-02-0-all-cpu-amplification.md +--- + src/capnp/arena.h | 11 +++++++++ + src/capnp/encoding-test.c++ | 30 ++++++++++++++++++++++++ + src/capnp/layout.c++ | 51 +++++++++++++++++++++++++++++++++++++---- + 3 files changed, 88 insertions(+), 4 deletions(-) + +diff --git a/src/capnp/arena.h b/src/capnp/arena.h +index 69316f982..53e17c0cb 100644 +--- a/src/capnp/arena.h ++++ b/src/capnp/arena.h +@@ -108,6 +108,13 @@ class SegmentReader { + + KJ_ALWAYS_INLINE(bool containsInterval(const void* from, const void* to)); + ++ KJ_ALWAYS_INLINE(bool amplifiedRead(WordCount virtualAmount)); ++ // Indicates that the reader should pretend that `virtualAmount` additional data was read even ++ // though no actual pointer was traversed. This is used e.g. when reading a struct list pointer ++ // where the element sizes are zero -- the sender could set the list size arbitrarily high and ++ // cause the receiver to iterate over this list even though the message itself is small, so we ++ // need to defend agaisnt DoS attacks based on this. ++ + inline Arena* getArena(); + inline SegmentId getSegmentId(); + +@@ -302,6 +309,10 @@ inline bool SegmentReader::containsInterval(const void* from, const void* to) { + arena); + } + ++inline bool SegmentReader::amplifiedRead(WordCount virtualAmount) { ++ return readLimiter->canRead(virtualAmount, arena); ++} ++ + inline Arena* SegmentReader::getArena() { return arena; } + inline SegmentId SegmentReader::getSegmentId() { return id; } + inline const word* SegmentReader::getStartPtr() { return ptr.begin(); } +diff --git a/src/capnp/encoding-test.c++ b/src/capnp/encoding-test.c++ +index c50d8ed89..1b08004db 100644 +--- a/src/capnp/encoding-test.c++ ++++ b/src/capnp/encoding-test.c++ +@@ -1484,6 +1484,36 @@ TEST(Encoding, Has) { + EXPECT_TRUE(root.asReader().hasInt32List()); + } + ++TEST(Encoding, VoidListAmplification) { ++ MallocMessageBuilder builder; ++ builder.initRoot().getAnyPointerField().initAs>(1u << 28); ++ ++ auto segments = builder.getSegmentsForOutput(); ++ EXPECT_EQ(1, segments.size()); ++ EXPECT_LT(segments[0].size(), 16); // quite small for such a big list! ++ ++ SegmentArrayMessageReader reader(builder.getSegmentsForOutput()); ++ auto root = reader.getRoot().getAnyPointerField(); ++ EXPECT_NONFATAL_FAILURE(root.getAs>()); ++ ++ MallocMessageBuilder copy; ++ EXPECT_NONFATAL_FAILURE(copy.setRoot(reader.getRoot())); ++} ++ ++TEST(Encoding, EmptyStructListAmplification) { ++ MallocMessageBuilder builder; ++ builder.initRoot().getAnyPointerField() ++ .initAs>(1u << 28); ++ ++ auto segments = builder.getSegmentsForOutput(); ++ EXPECT_EQ(1, segments.size()); ++ EXPECT_LT(segments[0].size(), 16); // quite small for such a big list! ++ ++ SegmentArrayMessageReader reader(builder.getSegmentsForOutput()); ++ auto root = reader.getRoot().getAnyPointerField(); ++ EXPECT_NONFATAL_FAILURE(root.getAs>()); ++} ++ + TEST(Encoding, Constants) { + EXPECT_EQ(VOID, test::TestConstants::VOID_CONST); + EXPECT_EQ(true, test::TestConstants::BOOL_CONST); +diff --git a/src/capnp/layout.c++ b/src/capnp/layout.c++ +index b0c09b7a5..d66e70b48 100644 +--- a/src/capnp/layout.c++ ++++ b/src/capnp/layout.c++ +@@ -308,6 +308,11 @@ struct WireHelpers { + return segment == nullptr || segment->containsInterval(start, end); + } + ++ static KJ_ALWAYS_INLINE(bool amplifiedRead(SegmentReader* segment, WordCount virtualAmount)) { ++ // If segment is null, this is an unchecked message, so we don't do read limiter checks. ++ return segment == nullptr || segment->amplifiedRead(virtualAmount); ++ } ++ + static KJ_ALWAYS_INLINE(word* allocate( + WirePointer*& ref, SegmentBuilder*& segment, WordCount amount, + WirePointer::Kind kind, BuilderArena* orphanArena)) { +@@ -1693,6 +1698,15 @@ struct WireHelpers { + goto useDefault; + } + ++ if (wordsPerElement * (1 * ELEMENTS) == 0 * WORDS) { ++ // Watch out for lists of zero-sized structs, which can claim to be arbitrarily large ++ // without having sent actual data. ++ KJ_REQUIRE(amplifiedRead(srcSegment, elementCount * (1 * WORDS / ELEMENTS)), ++ "Message contains amplified list pointer.") { ++ goto useDefault; ++ } ++ } ++ + return setListPointer(dstSegment, dst, + ListReader(srcSegment, ptr, elementCount, wordsPerElement * BITS_PER_WORD, + tag->structRef.dataSize.get() * BITS_PER_WORD, +@@ -1710,6 +1724,15 @@ struct WireHelpers { + goto useDefault; + } + ++ if (elementSize == FieldSize::VOID) { ++ // Watch out for lists of void, which can claim to be arbitrarily large without having ++ // sent actual data. ++ KJ_REQUIRE(amplifiedRead(srcSegment, elementCount * (1 * WORDS / ELEMENTS)), ++ "Message contains amplified list pointer.") { ++ goto useDefault; ++ } ++ } ++ + return setListPointer(dstSegment, dst, + ListReader(srcSegment, ptr, elementCount, step, dataSize, pointerCount, + nestingLimit - 1), +@@ -1907,7 +1930,8 @@ struct WireHelpers { + goto useDefault; + } + +- if (ref->listRef.elementSize() == FieldSize::INLINE_COMPOSITE) { ++ FieldSize elementSize = ref->listRef.elementSize(); ++ if (elementSize == FieldSize::INLINE_COMPOSITE) { + decltype(WORDS/ELEMENTS) wordsPerElement; + ElementCount size; + +@@ -1935,6 +1959,15 @@ struct WireHelpers { + goto useDefault; + } + ++ if (wordsPerElement * (1 * ELEMENTS) == 0 * WORDS) { ++ // Watch out for lists of zero-sized structs, which can claim to be arbitrarily large ++ // without having sent actual data. ++ KJ_REQUIRE(amplifiedRead(segment, size * (1 * WORDS / ELEMENTS)), ++ "Message contains amplified list pointer.") { ++ goto useDefault; ++ } ++ } ++ + // If a struct list was not expected, then presumably a non-struct list was upgraded to a + // struct list. We need to manipulate the pointer to point at the first field of the + // struct. Together with the "stepBits", this will allow the struct list to be accessed as +@@ -1982,14 +2015,24 @@ struct WireHelpers { + BitCount dataSize = dataBitsPerElement(ref->listRef.elementSize()) * ELEMENTS; + WirePointerCount pointerCount = + pointersPerElement(ref->listRef.elementSize()) * ELEMENTS; ++ ElementCount elementCount = ref->listRef.elementCount(); + auto step = (dataSize + pointerCount * BITS_PER_POINTER) / ELEMENTS; + +- KJ_REQUIRE(boundsCheck(segment, ptr, ptr + +- roundBitsUpToWords(ElementCount64(ref->listRef.elementCount()) * step)), ++ WordCount wordCount = roundBitsUpToWords(ElementCount64(elementCount) * step); ++ KJ_REQUIRE(boundsCheck(segment, ptr, ptr + wordCount), + "Message contains out-of-bounds list pointer.") { + goto useDefault; + } + ++ if (elementSize == FieldSize::VOID) { ++ // Watch out for lists of void, which can claim to be arbitrarily large without having sent ++ // actual data. ++ KJ_REQUIRE(amplifiedRead(segment, elementCount * (1 * WORDS / ELEMENTS)), ++ "Message contains amplified list pointer.") { ++ goto useDefault; ++ } ++ } ++ + // Verify that the elements are at least as large as the expected type. Note that if we + // expected INLINE_COMPOSITE, the expected sizes here will be zero, because bounds checking + // will be performed at field access time. So this check here is for the case where we +@@ -2009,7 +2052,7 @@ struct WireHelpers { + goto useDefault; + } + +- return ListReader(segment, ptr, ref->listRef.elementCount(), step, ++ return ListReader(segment, ptr, elementCount, step, + dataSize, pointerCount, nestingLimit - 1); + } + } diff -Nru capnproto-0.4.0/debian/patches/CVE-2015-2313.patch capnproto-0.4.0/debian/patches/CVE-2015-2313.patch --- capnproto-0.4.0/debian/patches/CVE-2015-2313.patch 1970-01-01 00:00:00.000000000 +0000 +++ capnproto-0.4.0/debian/patches/CVE-2015-2313.patch 2018-07-30 17:56:15.000000000 +0000 @@ -0,0 +1,125 @@ +From ac00109ca0749efd04a4203d002afa00f6b6cd89 Mon Sep 17 00:00:00 2001 +From: Kenton Varda +Date: Thu, 5 Mar 2015 10:27:29 -0800 +Subject: [PATCH] SECURITY: Additional CPU amplification case. + +Unfortunately, commit 104870608fde3c698483fdef6b97f093fc15685d missed a case of CPU amplification via struct lists with zero-sized elements. + +See advisory: https://github.com/sandstorm-io/capnproto/blob/master/security-advisories/2015-03-05-0-c++-addl-cpu-amplification.md +--- + src/capnp/encoding-test.c++ | 21 ++++++++++++++------- + src/capnp/layout.c++ | 42 +++++++++++++++++++++++------------------ + 2 files changed, 38 insertions(+), 25 deletions(-) + +diff --git a/src/capnp/encoding-test.c++ b/src/capnp/encoding-test.c++ +index 1b08004db..31de10dcc 100644 +--- a/src/capnp/encoding-test.c++ ++++ b/src/capnp/encoding-test.c++ +@@ -1501,17 +1501,24 @@ TEST(Encoding, VoidListAmplification) { + } + + TEST(Encoding, EmptyStructListAmplification) { +- MallocMessageBuilder builder; +- builder.initRoot().getAnyPointerField() +- .initAs>(1u << 28); ++ MallocMessageBuilder builder(1024); ++ auto listList = builder.initRoot().getAnyPointerField() ++ .initAs>>(500); ++ ++ for (uint i = 0; i < listList.size(); i++) { ++ listList.init(i, 1u << 28); ++ } + + auto segments = builder.getSegmentsForOutput(); +- EXPECT_EQ(1, segments.size()); +- EXPECT_LT(segments[0].size(), 16); // quite small for such a big list! ++ ASSERT_EQ(1, segments.size()); + + SegmentArrayMessageReader reader(builder.getSegmentsForOutput()); +- auto root = reader.getRoot().getAnyPointerField(); +- EXPECT_NONFATAL_FAILURE(root.getAs>()); ++ auto root = reader.getRoot(); ++ auto listListReader = root.getAnyPointerField().getAs>>(); ++ EXPECT_NONFATAL_FAILURE(listListReader[0]); ++ EXPECT_NONFATAL_FAILURE(listListReader[10]); ++ ++ EXPECT_EQ(segments[0].size() - 1, root.totalSize().wordCount); + } + + TEST(Encoding, Constants) { +diff --git a/src/capnp/layout.c++ b/src/capnp/layout.c++ +index d66e70b48..7a6993352 100644 +--- a/src/capnp/layout.c++ ++++ b/src/capnp/layout.c++ +@@ -534,14 +534,16 @@ struct WireHelpers { + WordCount dataSize = elementTag->structRef.dataSize.get(); + WirePointerCount pointerCount = elementTag->structRef.ptrCount.get(); + +- word* pos = ptr + POINTER_SIZE_IN_WORDS; + uint count = elementTag->inlineCompositeListElementCount() / ELEMENTS; +- for (uint i = 0; i < count; i++) { +- pos += dataSize; +- +- for (uint j = 0; j < pointerCount / POINTERS; j++) { +- zeroObject(segment, reinterpret_cast(pos)); +- pos += POINTER_SIZE_IN_WORDS; ++ if (pointerCount > 0 * POINTERS) { ++ word* pos = ptr + POINTER_SIZE_IN_WORDS; ++ for (uint i = 0; i < count; i++) { ++ pos += dataSize; ++ ++ for (uint j = 0; j < pointerCount / POINTERS; j++) { ++ zeroObject(segment, reinterpret_cast(pos)); ++ pos += POINTER_SIZE_IN_WORDS; ++ } + } + } + +@@ -657,8 +659,6 @@ struct WireHelpers { + return result; + } + +- result.wordCount += wordCount + POINTER_SIZE_IN_WORDS; +- + const WirePointer* elementTag = reinterpret_cast(ptr); + ElementCount count = elementTag->inlineCompositeListElementCount(); + +@@ -667,23 +667,29 @@ struct WireHelpers { + return result; + } + +- KJ_REQUIRE(elementTag->structRef.wordSize() / ELEMENTS * +- ElementCount64(count) <= wordCount, ++ auto actualSize = elementTag->structRef.wordSize() / ELEMENTS * ElementCount64(count); ++ KJ_REQUIRE(actualSize <= wordCount, + "Struct list pointer's elements overran size.") { + return result; + } + ++ // We count the actual size rather than the claimed word count because that's what ++ // we'll end up with if we make a copy. ++ result.wordCount += actualSize + POINTER_SIZE_IN_WORDS; ++ + WordCount dataSize = elementTag->structRef.dataSize.get(); + WirePointerCount pointerCount = elementTag->structRef.ptrCount.get(); + +- const word* pos = ptr + POINTER_SIZE_IN_WORDS; +- for (uint i = 0; i < count / ELEMENTS; i++) { +- pos += dataSize; ++ if (pointerCount > 0 * POINTERS) { ++ const word* pos = ptr + POINTER_SIZE_IN_WORDS; ++ for (uint i = 0; i < count / ELEMENTS; i++) { ++ pos += dataSize; + +- for (uint j = 0; j < pointerCount / POINTERS; j++) { +- result += totalSize(segment, reinterpret_cast(pos), +- nestingLimit); +- pos += POINTER_SIZE_IN_WORDS; ++ for (uint j = 0; j < pointerCount / POINTERS; j++) { ++ result += totalSize(segment, reinterpret_cast(pos), ++ nestingLimit); ++ pos += POINTER_SIZE_IN_WORDS; ++ } + } + } + break; diff -Nru capnproto-0.4.0/debian/patches/CVE-2017-7892.patch capnproto-0.4.0/debian/patches/CVE-2017-7892.patch --- capnproto-0.4.0/debian/patches/CVE-2017-7892.patch 1970-01-01 00:00:00.000000000 +0000 +++ capnproto-0.4.0/debian/patches/CVE-2017-7892.patch 2018-07-30 18:21:01.000000000 +0000 @@ -0,0 +1,30 @@ +From 51e801a705b1cf40eb3d21f9dd2038edba4d8b2e Mon Sep 17 00:00:00 2001 +From: Kenton Varda +Date: Sat, 15 Apr 2017 19:31:53 -0700 +Subject: [PATCH] SECURITY: Prevent compiler from eliding bounds checks. + +Details: https://github.com/sandstorm-io/capnproto/blob/master/security-advisories/2017-04-17-0-apple-32bit-elides-bounds-check.md +--- + src/capnp/arena.h | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/capnp/arena.h b/src/capnp/arena.h +index 8edd9bb8..74238a6c 100644 +--- a/src/capnp/arena.h ++++ b/src/capnp/arena.h +@@ -295,7 +295,11 @@ inline SegmentReader::SegmentReader(Arena* arena, SegmentId id, kj::ArrayPtr= this->ptr.begin() && to <= this->ptr.end() && ++ uintptr_t start = reinterpret_cast(from) - reinterpret_cast(ptr.begin()); ++ uintptr_t end = reinterpret_cast(to) - reinterpret_cast(ptr.begin()); ++ uintptr_t bound = ptr.size() * sizeof(capnp::word); ++ ++ return start <= bound && end <= bound && start <= end && + readLimiter->canRead( + intervalLength(reinterpret_cast(from), + reinterpret_cast(to)) / BYTES_PER_WORD, +-- +2.17.1 + diff -Nru capnproto-0.4.0/debian/patches/series capnproto-0.4.0/debian/patches/series --- capnproto-0.4.0/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ capnproto-0.4.0/debian/patches/series 2018-07-30 18:12:45.000000000 +0000 @@ -0,0 +1,5 @@ +CVE-2015-2310.patch +CVE-2015-2311.patch +CVE-2015-2312.patch +CVE-2015-2313.patch +CVE-2017-7892.patch