aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-04-02 23:20:37 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-04-02 23:20:37 +0000
commit36f034d9ef56ee7a1f95b57f8c557728bbdfc85c (patch)
tree90778b6c1a52923d738f7239b9fc583d1bf6f879
parentbfa013367f4d036204fa5b2a5d62ace9273cbd22 (diff)
parent6303c829c36e63fcaca727fa5b6bea052b61af25 (diff)
downloadlibcppbor-sdk-release.tar.gz
Snap for 11662267 from 6303c829c36e63fcaca727fa5b6bea052b61af25 to sdk-releasesdk-release
Change-Id: I32c8dc1728a9368ef654f470d7f5fe741f04ab34
-rw-r--r--Android.bp37
-rw-r--r--src/cppbor_parse.cpp42
-rw-r--r--tests/cppbor_test.cpp25
3 files changed, 83 insertions, 21 deletions
diff --git a/Android.bp b/Android.bp
index 5b82c48..72f421a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -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);