1 /*
2 * Copyright 2019 Google LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "cppbor_parse.h"
18
19 #include <memory>
20 #include <sstream>
21 #include <stack>
22 #include <type_traits>
23 #include "cppbor.h"
24
25 #ifndef __TRUSTY__
26 #include <android-base/logging.h>
27 #define LOG_TAG "CppBor"
28 #else
29 #define CHECK(x) (void)(x)
30 #endif
31
32 namespace cppbor {
33
34 namespace {
35
36 const unsigned kMaxParseDepth = 1000;
37
insufficientLengthString(size_t bytesNeeded,size_t bytesAvail,const std::string & type)38 std::string insufficientLengthString(size_t bytesNeeded, size_t bytesAvail,
39 const std::string& type) {
40 char buf[1024];
41 snprintf(buf, sizeof(buf), "Need %zu byte(s) for %s, have %zu.", bytesNeeded, type.c_str(),
42 bytesAvail);
43 return std::string(buf);
44 }
45
46 template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
parseLength(const uint8_t * pos,const uint8_t * end,ParseClient * parseClient)47 std::tuple<bool, uint64_t, const uint8_t*> parseLength(const uint8_t* pos, const uint8_t* end,
48 ParseClient* parseClient) {
49 if (pos + sizeof(T) > end) {
50 parseClient->error(pos - 1, insufficientLengthString(sizeof(T), end - pos, "length field"));
51 return {false, 0, pos};
52 }
53
54 const uint8_t* intEnd = pos + sizeof(T);
55 T result = 0;
56 do {
57 result = static_cast<T>((result << 8) | *pos++);
58 } while (pos < intEnd);
59 return {true, result, pos};
60 }
61
62 std::tuple<const uint8_t*, ParseClient*> parseRecursively(const uint8_t* begin, const uint8_t* end,
63 bool emitViews, ParseClient* parseClient,
64 unsigned depth);
65
handleUint(uint64_t value,const uint8_t * hdrBegin,const uint8_t * hdrEnd,ParseClient * parseClient)66 std::tuple<const uint8_t*, ParseClient*> handleUint(uint64_t value, const uint8_t* hdrBegin,
67 const uint8_t* hdrEnd,
68 ParseClient* parseClient) {
69 std::unique_ptr<Item> item = std::make_unique<Uint>(value);
70 return {hdrEnd,
71 parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
72 }
73
handleNint(uint64_t value,const uint8_t * hdrBegin,const uint8_t * hdrEnd,ParseClient * parseClient)74 std::tuple<const uint8_t*, ParseClient*> handleNint(uint64_t value, const uint8_t* hdrBegin,
75 const uint8_t* hdrEnd,
76 ParseClient* parseClient) {
77 if (value > std::numeric_limits<int64_t>::max()) {
78 parseClient->error(hdrBegin, "NINT values that don't fit in int64_t are not supported.");
79 return {hdrBegin, nullptr /* end parsing */};
80 }
81 std::unique_ptr<Item> item = std::make_unique<Nint>(-1 - static_cast<int64_t>(value));
82 return {hdrEnd,
83 parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
84 }
85
handleBool(uint64_t value,const uint8_t * hdrBegin,const uint8_t * hdrEnd,ParseClient * parseClient)86 std::tuple<const uint8_t*, ParseClient*> handleBool(uint64_t value, const uint8_t* hdrBegin,
87 const uint8_t* hdrEnd,
88 ParseClient* parseClient) {
89 std::unique_ptr<Item> item = std::make_unique<Bool>(value == TRUE);
90 return {hdrEnd,
91 parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
92 }
93
handleNull(const uint8_t * hdrBegin,const uint8_t * hdrEnd,ParseClient * parseClient)94 std::tuple<const uint8_t*, ParseClient*> handleNull(const uint8_t* hdrBegin, const uint8_t* hdrEnd,
95 ParseClient* parseClient) {
96 std::unique_ptr<Item> item = std::make_unique<Null>();
97 return {hdrEnd,
98 parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
99 }
100
101 template <typename T>
handleString(uint64_t length,const uint8_t * hdrBegin,const uint8_t * valueBegin,const uint8_t * end,const std::string & errLabel,ParseClient * parseClient)102 std::tuple<const uint8_t*, ParseClient*> handleString(uint64_t length, const uint8_t* hdrBegin,
103 const uint8_t* valueBegin, const uint8_t* end,
104 const std::string& errLabel,
105 ParseClient* parseClient) {
106 ssize_t signed_length = static_cast<ssize_t>(length);
107 if (end - valueBegin < signed_length || signed_length < 0) {
108 parseClient->error(hdrBegin, insufficientLengthString(length, end - valueBegin, errLabel));
109 return {hdrBegin, nullptr /* end parsing */};
110 }
111
112 std::unique_ptr<Item> item = std::make_unique<T>(valueBegin, valueBegin + length);
113 return {valueBegin + length,
114 parseClient->item(item, hdrBegin, valueBegin, valueBegin + length)};
115 }
116
117 class IncompleteItem {
118 public:
119 static IncompleteItem* cast(Item* item);
120
~IncompleteItem()121 virtual ~IncompleteItem() {}
122 virtual void add(std::unique_ptr<Item> item) = 0;
123 virtual std::unique_ptr<Item> finalize() && = 0;
124 };
125
126 class IncompleteArray : public Array, public IncompleteItem {
127 public:
IncompleteArray(size_t size)128 explicit IncompleteArray(size_t size) : mSize(size) {}
129
130 // We return the "complete" size, rather than the actual size.
size() const131 size_t size() const override { return mSize; }
132
add(std::unique_ptr<Item> item)133 void add(std::unique_ptr<Item> item) override {
134 mEntries.push_back(std::move(item));
135 }
136
finalize()137 virtual std::unique_ptr<Item> finalize() && override {
138 // Use Array explicitly so the compiler picks the correct ctor overload
139 Array* thisArray = this;
140 return std::make_unique<Array>(std::move(*thisArray));
141 }
142
143 private:
144 size_t mSize;
145 };
146
147 class IncompleteMap : public Map, public IncompleteItem {
148 public:
IncompleteMap(size_t size)149 explicit IncompleteMap(size_t size) : mSize(size) {}
150
151 // We return the "complete" size, rather than the actual size.
size() const152 size_t size() const override { return mSize; }
153
add(std::unique_ptr<Item> item)154 void add(std::unique_ptr<Item> item) override {
155 if (mKeyHeldForAdding) {
156 mEntries.push_back({std::move(mKeyHeldForAdding), std::move(item)});
157 } else {
158 mKeyHeldForAdding = std::move(item);
159 }
160 }
161
finalize()162 virtual std::unique_ptr<Item> finalize() && override {
163 return std::make_unique<Map>(std::move(*this));
164 }
165
166 private:
167 std::unique_ptr<Item> mKeyHeldForAdding;
168 size_t mSize;
169 };
170
171 class IncompleteSemanticTag : public SemanticTag, public IncompleteItem {
172 public:
IncompleteSemanticTag(uint64_t value)173 explicit IncompleteSemanticTag(uint64_t value) : SemanticTag(value) {}
174
175 // We return the "complete" size, rather than the actual size.
size() const176 size_t size() const override { return 1; }
177
add(std::unique_ptr<Item> item)178 void add(std::unique_ptr<Item> item) override { mTaggedItem = std::move(item); }
179
finalize()180 virtual std::unique_ptr<Item> finalize() && override {
181 return std::make_unique<SemanticTag>(std::move(*this));
182 }
183 };
184
cast(Item * item)185 IncompleteItem* IncompleteItem::cast(Item* item) {
186 CHECK(item->isCompound());
187 // Semantic tag must be check first, because SemanticTag::type returns the wrapped item's type.
188 if (item->asSemanticTag()) {
189 #if __has_feature(cxx_rtti)
190 CHECK(dynamic_cast<IncompleteSemanticTag*>(item));
191 #endif
192 return static_cast<IncompleteSemanticTag*>(item);
193 } else if (item->type() == ARRAY) {
194 #if __has_feature(cxx_rtti)
195 CHECK(dynamic_cast<IncompleteArray*>(item));
196 #endif
197 return static_cast<IncompleteArray*>(item);
198 } else if (item->type() == MAP) {
199 #if __has_feature(cxx_rtti)
200 CHECK(dynamic_cast<IncompleteMap*>(item));
201 #endif
202 return static_cast<IncompleteMap*>(item);
203 } else {
204 CHECK(false); // Impossible to get here.
205 }
206 return nullptr;
207 }
208
handleEntries(size_t entryCount,const uint8_t * hdrBegin,const uint8_t * pos,const uint8_t * end,const std::string & typeName,bool emitViews,ParseClient * parseClient,unsigned depth)209 std::tuple<const uint8_t*, ParseClient*> handleEntries(size_t entryCount, const uint8_t* hdrBegin,
210 const uint8_t* pos, const uint8_t* end,
211 const std::string& typeName, bool emitViews,
212 ParseClient* parseClient, unsigned depth) {
213 while (entryCount > 0) {
214 --entryCount;
215 if (pos == end) {
216 parseClient->error(hdrBegin, "Not enough entries for " + typeName + ".");
217 return {hdrBegin, nullptr /* end parsing */};
218 }
219 std::tie(pos, parseClient) = parseRecursively(pos, end, emitViews, parseClient, depth + 1);
220 if (!parseClient) return {hdrBegin, nullptr};
221 }
222 return {pos, parseClient};
223 }
224
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,unsigned depth)225 std::tuple<const uint8_t*, ParseClient*> handleCompound(
226 std::unique_ptr<Item> item, uint64_t entryCount, const uint8_t* hdrBegin,
227 const uint8_t* valueBegin, const uint8_t* end, const std::string& typeName, bool emitViews,
228 ParseClient* parseClient, unsigned depth) {
229 parseClient =
230 parseClient->item(item, hdrBegin, valueBegin, valueBegin /* don't know the end yet */);
231 if (!parseClient) return {hdrBegin, nullptr};
232
233 const uint8_t* pos;
234 std::tie(pos, parseClient) = handleEntries(entryCount, hdrBegin, valueBegin, end, typeName,
235 emitViews, parseClient, depth);
236 if (!parseClient) return {hdrBegin, nullptr};
237
238 return {pos, parseClient->itemEnd(item, hdrBegin, valueBegin, pos)};
239 }
240
parseRecursively(const uint8_t * begin,const uint8_t * end,bool emitViews,ParseClient * parseClient,unsigned depth)241 std::tuple<const uint8_t*, ParseClient*> parseRecursively(const uint8_t* begin, const uint8_t* end,
242 bool emitViews, ParseClient* parseClient,
243 unsigned depth) {
244 if (begin == end) {
245 parseClient->error(
246 begin,
247 "Input buffer is empty. Begin and end cannot point to the same location.");
248 return {begin, nullptr};
249 }
250
251 // Limit recursion depth to avoid overflowing the stack.
252 if (depth > kMaxParseDepth) {
253 parseClient->error(begin,
254 "Max depth reached. Cannot parse CBOR structures with more "
255 "than " +
256 std::to_string(kMaxParseDepth) + " levels.");
257 return {begin, nullptr};
258 }
259
260 const uint8_t* pos = begin;
261
262 MajorType type = static_cast<MajorType>(*pos & 0xE0);
263 uint8_t tagInt = *pos & 0x1F;
264 ++pos;
265
266 bool success = true;
267 uint64_t addlData;
268 if (tagInt < ONE_BYTE_LENGTH) {
269 addlData = tagInt;
270 } else if (tagInt > EIGHT_BYTE_LENGTH) {
271 parseClient->error(
272 begin,
273 "Reserved additional information value or unsupported indefinite length item.");
274 return {begin, nullptr};
275 } else {
276 switch (tagInt) {
277 case ONE_BYTE_LENGTH:
278 std::tie(success, addlData, pos) = parseLength<uint8_t>(pos, end, parseClient);
279 break;
280
281 case TWO_BYTE_LENGTH:
282 std::tie(success, addlData, pos) = parseLength<uint16_t>(pos, end, parseClient);
283 break;
284
285 case FOUR_BYTE_LENGTH:
286 std::tie(success, addlData, pos) = parseLength<uint32_t>(pos, end, parseClient);
287 break;
288
289 case EIGHT_BYTE_LENGTH:
290 std::tie(success, addlData, pos) = parseLength<uint64_t>(pos, end, parseClient);
291 break;
292
293 default:
294 CHECK(false); // It's impossible to get here
295 break;
296 }
297 }
298
299 if (!success) return {begin, nullptr};
300
301 switch (type) {
302 case UINT:
303 return handleUint(addlData, begin, pos, parseClient);
304
305 case NINT:
306 return handleNint(addlData, begin, pos, parseClient);
307
308 case BSTR:
309 if (emitViews) {
310 return handleString<ViewBstr>(addlData, begin, pos, end, "byte string", parseClient);
311 } else {
312 return handleString<Bstr>(addlData, begin, pos, end, "byte string", parseClient);
313 }
314
315 case TSTR:
316 if (emitViews) {
317 return handleString<ViewTstr>(addlData, begin, pos, end, "text string", parseClient);
318 } else {
319 return handleString<Tstr>(addlData, begin, pos, end, "text string", parseClient);
320 }
321
322 case ARRAY:
323 return handleCompound(std::make_unique<IncompleteArray>(addlData), addlData, begin, pos,
324 end, "array", emitViews, parseClient, depth);
325
326 case MAP:
327 return handleCompound(std::make_unique<IncompleteMap>(addlData), addlData * 2, begin,
328 pos, end, "map", emitViews, parseClient, depth);
329
330 case SEMANTIC:
331 return handleCompound(std::make_unique<IncompleteSemanticTag>(addlData), 1, begin, pos,
332 end, "semantic", emitViews, parseClient, depth);
333
334 case SIMPLE:
335 switch (addlData) {
336 case TRUE:
337 case FALSE:
338 return handleBool(addlData, begin, pos, parseClient);
339 case NULL_V:
340 return handleNull(begin, pos, parseClient);
341 default:
342 parseClient->error(begin, "Unsupported floating-point or simple value.");
343 return {begin, nullptr};
344 }
345 }
346 CHECK(false); // Impossible to get here.
347 return {};
348 }
349
350 class FullParseClient : public ParseClient {
351 public:
item(std::unique_ptr<Item> & item,const uint8_t *,const uint8_t *,const uint8_t * end)352 virtual ParseClient* item(std::unique_ptr<Item>& item, const uint8_t*, const uint8_t*,
353 const uint8_t* end) override {
354 if (mParentStack.empty() && !item->isCompound()) {
355 // This is the first and only item.
356 mTheItem = std::move(item);
357 mPosition = end;
358 return nullptr; // We're done.
359 }
360
361 if (item->isCompound()) {
362 // Starting a new compound data item, i.e. a new parent. Save it on the parent stack.
363 // It's safe to save a raw pointer because the unique_ptr is guaranteed to stay in
364 // existence until the corresponding itemEnd() call.
365 mParentStack.push(item.get());
366 return this;
367 } else {
368 appendToLastParent(std::move(item));
369 return this;
370 }
371 }
372
itemEnd(std::unique_ptr<Item> & item,const uint8_t *,const uint8_t *,const uint8_t * end)373 virtual ParseClient* itemEnd(std::unique_ptr<Item>& item, const uint8_t*, const uint8_t*,
374 const uint8_t* end) override {
375 CHECK(item->isCompound() && item.get() == mParentStack.top());
376 mParentStack.pop();
377 IncompleteItem* incompleteItem = IncompleteItem::cast(item.get());
378 std::unique_ptr<Item> finalizedItem = std::move(*incompleteItem).finalize();
379
380 if (mParentStack.empty()) {
381 mTheItem = std::move(finalizedItem);
382 mPosition = end;
383 return nullptr; // We're done
384 } else {
385 appendToLastParent(std::move(finalizedItem));
386 return this;
387 }
388 }
389
error(const uint8_t * position,const std::string & errorMessage)390 virtual void error(const uint8_t* position, const std::string& errorMessage) override {
391 mPosition = position;
392 mErrorMessage = errorMessage;
393 }
394
395 std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
396 std::string /* errMsg */>
parseResult()397 parseResult() {
398 std::unique_ptr<Item> p = std::move(mTheItem);
399 return {std::move(p), mPosition, std::move(mErrorMessage)};
400 }
401
402 private:
appendToLastParent(std::unique_ptr<Item> item)403 void appendToLastParent(std::unique_ptr<Item> item) {
404 auto parent = mParentStack.top();
405 IncompleteItem::cast(parent)->add(std::move(item));
406 }
407
408 std::unique_ptr<Item> mTheItem;
409 std::stack<Item*> mParentStack;
410 const uint8_t* mPosition = nullptr;
411 std::string mErrorMessage;
412 };
413
414 } // anonymous namespace
415
parse(const uint8_t * begin,const uint8_t * end,ParseClient * parseClient)416 void parse(const uint8_t* begin, const uint8_t* end, ParseClient* parseClient) {
417 parseRecursively(begin, end, false, parseClient, 0);
418 }
419
420 std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
421 std::string /* errMsg */>
parse(const uint8_t * begin,const uint8_t * end)422 parse(const uint8_t* begin, const uint8_t* end) {
423 FullParseClient parseClient;
424 parse(begin, end, &parseClient);
425 return parseClient.parseResult();
426 }
427
parseWithViews(const uint8_t * begin,const uint8_t * end,ParseClient * parseClient)428 void parseWithViews(const uint8_t* begin, const uint8_t* end, ParseClient* parseClient) {
429 parseRecursively(begin, end, true, parseClient, 0);
430 }
431
432 std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
433 std::string /* errMsg */>
parseWithViews(const uint8_t * begin,const uint8_t * end)434 parseWithViews(const uint8_t* begin, const uint8_t* end) {
435 FullParseClient parseClient;
436 parseWithViews(begin, end, &parseClient);
437 return parseClient.parseResult();
438 }
439
440 } // namespace cppbor
441