• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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