diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-04-02 23:20:37 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-04-02 23:20:37 +0000 |
commit | 36f034d9ef56ee7a1f95b57f8c557728bbdfc85c (patch) | |
tree | 90778b6c1a52923d738f7239b9fc583d1bf6f879 | |
parent | bfa013367f4d036204fa5b2a5d62ace9273cbd22 (diff) | |
parent | 6303c829c36e63fcaca727fa5b6bea052b61af25 (diff) | |
download | libcppbor-sdk-release.tar.gz |
Snap for 11662267 from 6303c829c36e63fcaca727fa5b6bea052b61af25 to sdk-releasesdk-release
Change-Id: I32c8dc1728a9368ef654f470d7f5fe741f04ab34
-rw-r--r-- | Android.bp | 37 | ||||
-rw-r--r-- | src/cppbor_parse.cpp | 42 | ||||
-rw-r--r-- | tests/cppbor_test.cpp | 25 |
3 files changed, 83 insertions, 21 deletions
@@ -14,13 +14,13 @@ package { default_team: "trendy_team_android_hardware_backed_security", - default_applicable_licenses: ["external_libcppbor_license"], + default_applicable_licenses: ["libcppbor_license"], } // Added automatically by a large-scale-change // See: http://go/android-license-faq license { - name: "external_libcppbor_license", + name: "libcppbor_license", visibility: [":__subpackages__"], license_kinds: [ "SPDX-license-identifier-Apache-2.0", @@ -40,6 +40,31 @@ cc_defaults { } cc_library { + name: "libcppbor", + defaults: [ + "libcppbor_defaults", + ], + vendor_available: true, + host_supported: true, + srcs: [ + "src/cppbor.cpp", + "src/cppbor_parse.cpp", + ], + export_include_dirs: [ + "include/cppbor", + ], + shared_libs: [ + "libbase", + "libcrypto", + ], + target: { + windows: { + enabled: true, + }, + }, +} + +cc_library { name: "libcppbor_external", defaults: [ "libcppbor_defaults", @@ -65,7 +90,7 @@ cc_library { } cc_test { - name: "cppbor_test_external", + name: "cppbor_test", defaults: [ "libcppbor_defaults", ], @@ -73,7 +98,7 @@ cc_test { "tests/cppbor_test.cpp", ], shared_libs: [ - "libcppbor_external", + "libcppbor", "libbase", ], static_libs: [ @@ -83,7 +108,7 @@ cc_test { } cc_test_host { - name: "cppbor_host_test_external", + name: "cppbor_host_test", defaults: [ "libcppbor_defaults", ], @@ -91,7 +116,7 @@ cc_test_host { "tests/cppbor_test.cpp", ], shared_libs: [ - "libcppbor_external", + "libcppbor", "libbase", ], static_libs: [ diff --git a/src/cppbor_parse.cpp b/src/cppbor_parse.cpp index 2614c4e..c3fa070 100644 --- a/src/cppbor_parse.cpp +++ b/src/cppbor_parse.cpp @@ -33,6 +33,8 @@ namespace cppbor { namespace { +const unsigned kMaxParseDepth = 1000; + std::string insufficientLengthString(size_t bytesNeeded, size_t bytesAvail, const std::string& type) { char buf[1024]; @@ -58,7 +60,8 @@ std::tuple<bool, uint64_t, const uint8_t*> parseLength(const uint8_t* pos, const } std::tuple<const uint8_t*, ParseClient*> parseRecursively(const uint8_t* begin, const uint8_t* end, - bool emitViews, ParseClient* parseClient); + bool emitViews, ParseClient* parseClient, + unsigned depth); std::tuple<const uint8_t*, ParseClient*> handleUint(uint64_t value, const uint8_t* hdrBegin, const uint8_t* hdrEnd, @@ -205,16 +208,15 @@ IncompleteItem* IncompleteItem::cast(Item* item) { std::tuple<const uint8_t*, ParseClient*> handleEntries(size_t entryCount, const uint8_t* hdrBegin, const uint8_t* pos, const uint8_t* end, - const std::string& typeName, - bool emitViews, - ParseClient* parseClient) { + const std::string& typeName, bool emitViews, + ParseClient* parseClient, unsigned depth) { while (entryCount > 0) { --entryCount; if (pos == end) { parseClient->error(hdrBegin, "Not enough entries for " + typeName + "."); return {hdrBegin, nullptr /* end parsing */}; } - std::tie(pos, parseClient) = parseRecursively(pos, end, emitViews, parseClient); + std::tie(pos, parseClient) = parseRecursively(pos, end, emitViews, parseClient, depth + 1); if (!parseClient) return {hdrBegin, nullptr}; } return {pos, parseClient}; @@ -222,22 +224,23 @@ std::tuple<const uint8_t*, ParseClient*> handleEntries(size_t entryCount, const std::tuple<const uint8_t*, ParseClient*> handleCompound( std::unique_ptr<Item> item, uint64_t entryCount, const uint8_t* hdrBegin, - const uint8_t* valueBegin, const uint8_t* end, const std::string& typeName, - bool emitViews, ParseClient* parseClient) { + const uint8_t* valueBegin, const uint8_t* end, const std::string& typeName, bool emitViews, + ParseClient* parseClient, unsigned depth) { parseClient = parseClient->item(item, hdrBegin, valueBegin, valueBegin /* don't know the end yet */); if (!parseClient) return {hdrBegin, nullptr}; const uint8_t* pos; - std::tie(pos, parseClient) = - handleEntries(entryCount, hdrBegin, valueBegin, end, typeName, emitViews, parseClient); + std::tie(pos, parseClient) = handleEntries(entryCount, hdrBegin, valueBegin, end, typeName, + emitViews, parseClient, depth); if (!parseClient) return {hdrBegin, nullptr}; return {pos, parseClient->itemEnd(item, hdrBegin, valueBegin, pos)}; } std::tuple<const uint8_t*, ParseClient*> parseRecursively(const uint8_t* begin, const uint8_t* end, - bool emitViews, ParseClient* parseClient) { + bool emitViews, ParseClient* parseClient, + unsigned depth) { if (begin == end) { parseClient->error( begin, @@ -245,6 +248,15 @@ std::tuple<const uint8_t*, ParseClient*> parseRecursively(const uint8_t* begin, return {begin, nullptr}; } + // Limit recursion depth to avoid overflowing the stack. + if (depth > kMaxParseDepth) { + parseClient->error(begin, + "Max depth reached. Cannot parse CBOR structures with more " + "than " + + std::to_string(kMaxParseDepth) + " levels."); + return {begin, nullptr}; + } + const uint8_t* pos = begin; MajorType type = static_cast<MajorType>(*pos & 0xE0); @@ -309,15 +321,15 @@ std::tuple<const uint8_t*, ParseClient*> parseRecursively(const uint8_t* begin, case ARRAY: return handleCompound(std::make_unique<IncompleteArray>(addlData), addlData, begin, pos, - end, "array", emitViews, parseClient); + end, "array", emitViews, parseClient, depth); case MAP: return handleCompound(std::make_unique<IncompleteMap>(addlData), addlData * 2, begin, - pos, end, "map", emitViews, parseClient); + pos, end, "map", emitViews, parseClient, depth); case SEMANTIC: return handleCompound(std::make_unique<IncompleteSemanticTag>(addlData), 1, begin, pos, - end, "semantic", emitViews, parseClient); + end, "semantic", emitViews, parseClient, depth); case SIMPLE: switch (addlData) { @@ -402,7 +414,7 @@ class FullParseClient : public ParseClient { } // anonymous namespace void parse(const uint8_t* begin, const uint8_t* end, ParseClient* parseClient) { - parseRecursively(begin, end, false, parseClient); + parseRecursively(begin, end, false, parseClient, 0); } std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */, @@ -414,7 +426,7 @@ parse(const uint8_t* begin, const uint8_t* end) { } void parseWithViews(const uint8_t* begin, const uint8_t* end, ParseClient* parseClient) { - parseRecursively(begin, end, true, parseClient); + parseRecursively(begin, end, true, parseClient, 0); } std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */, diff --git a/tests/cppbor_test.cpp b/tests/cppbor_test.cpp index a75acc8..fadcaa9 100644 --- a/tests/cppbor_test.cpp +++ b/tests/cppbor_test.cpp @@ -33,6 +33,7 @@ using ::testing::InSequence; using ::testing::IsNull; using ::testing::NotNull; using ::testing::Return; +using ::testing::StartsWith; using ::testing::Unused; string hexDump(const string& str) { @@ -1579,6 +1580,30 @@ TEST(StreamParseTest, ViewBstr) { parseWithViews(encoded.data(), encoded.data() + encoded.size(), &mpc); } +TEST(StreamParseTest, AllowDepth1000) { + std::vector<uint8_t> data(/* count */ 1000, /* value = array with one entry */ 0x81); + data.push_back(0); + + MockParseClient mpc; + EXPECT_CALL(mpc, item).Times(1001).WillRepeatedly(Return(&mpc)); + EXPECT_CALL(mpc, itemEnd).Times(1000).WillRepeatedly(Return(&mpc)); + EXPECT_CALL(mpc, error(_, _)).Times(0); + + parse(data.data(), data.data() + data.size(), &mpc); +} + +TEST(StreamParseTest, DisallowDepth1001) { + std::vector<uint8_t> data(/* count */ 1001, /* value = array with one entry */ 0x81); + data.push_back(0); + + MockParseClient mpc; + EXPECT_CALL(mpc, item).Times(1001).WillRepeatedly(Return(&mpc)); + EXPECT_CALL(mpc, itemEnd).Times(0); + EXPECT_CALL(mpc, error(_, StartsWith("Max depth reached"))).Times(1); + + parse(data.data(), data.data() + data.size(), &mpc); +} + TEST(FullParserTest, Uint) { Uint val(10); |