• 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 <stack>
20 
21 #ifndef __TRUSTY__
22 #include <android-base/logging.h>
23 #define LOG_TAG "CppBor"
24 #else
25 #define CHECK(x) (void)(x)
26 #endif
27 
28 namespace cppbor {
29 
30 namespace {
31 
insufficientLengthString(size_t bytesNeeded,size_t bytesAvail,const std::string & type)32 std::string insufficientLengthString(size_t bytesNeeded, size_t bytesAvail,
33                                      const std::string& type) {
34     char buf[1024];
35     snprintf(buf, sizeof(buf), "Need %zu byte(s) for %s, have %zu.", bytesNeeded, type.c_str(),
36              bytesAvail);
37     return std::string(buf);
38 }
39 
40 template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
parseLength(const uint8_t * pos,const uint8_t * end,ParseClient * parseClient)41 std::tuple<bool, uint64_t, const uint8_t*> parseLength(const uint8_t* pos, const uint8_t* end,
42                                                        ParseClient* parseClient) {
43     if (pos + sizeof(T) > end) {
44         parseClient->error(pos - 1, insufficientLengthString(sizeof(T), end - pos, "length field"));
45         return {false, 0, pos};
46     }
47 
48     const uint8_t* intEnd = pos + sizeof(T);
49     T result = 0;
50     do {
51         result = static_cast<T>((result << 8) | *pos++);
52     } while (pos < intEnd);
53     return {true, result, pos};
54 }
55 
56 std::tuple<const uint8_t*, ParseClient*> parseRecursively(const uint8_t* begin, const uint8_t* end,
57                                                           bool emitViews, ParseClient* parseClient);
58 
handleUint(uint64_t value,const uint8_t * hdrBegin,const uint8_t * hdrEnd,ParseClient * parseClient)59 std::tuple<const uint8_t*, ParseClient*> handleUint(uint64_t value, const uint8_t* hdrBegin,
60                                                     const uint8_t* hdrEnd,
61                                                     ParseClient* parseClient) {
62     std::unique_ptr<Item> item = std::make_unique<Uint>(value);
63     return {hdrEnd,
64             parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
65 }
66 
handleNint(uint64_t value,const uint8_t * hdrBegin,const uint8_t * hdrEnd,ParseClient * parseClient)67 std::tuple<const uint8_t*, ParseClient*> handleNint(uint64_t value, const uint8_t* hdrBegin,
68                                                     const uint8_t* hdrEnd,
69                                                     ParseClient* parseClient) {
70     if (value > std::numeric_limits<int64_t>::max()) {
71         parseClient->error(hdrBegin, "NINT values that don't fit in int64_t are not supported.");
72         return {hdrBegin, nullptr /* end parsing */};
73     }
74     std::unique_ptr<Item> item = std::make_unique<Nint>(-1 - static_cast<int64_t>(value));
75     return {hdrEnd,
76             parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
77 }
78 
handleBool(uint64_t value,const uint8_t * hdrBegin,const uint8_t * hdrEnd,ParseClient * parseClient)79 std::tuple<const uint8_t*, ParseClient*> handleBool(uint64_t value, const uint8_t* hdrBegin,
80                                                     const uint8_t* hdrEnd,
81                                                     ParseClient* parseClient) {
82     std::unique_ptr<Item> item = std::make_unique<Bool>(value == TRUE);
83     return {hdrEnd,
84             parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
85 }
86 
handleNull(const uint8_t * hdrBegin,const uint8_t * hdrEnd,ParseClient * parseClient)87 std::tuple<const uint8_t*, ParseClient*> handleNull(const uint8_t* hdrBegin, const uint8_t* hdrEnd,
88                                                     ParseClient* parseClient) {
89     std::unique_ptr<Item> item = std::make_unique<Null>();
90     return {hdrEnd,
91             parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
92 }
93 
94 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)95 std::tuple<const uint8_t*, ParseClient*> handleString(uint64_t length, const uint8_t* hdrBegin,
96                                                       const uint8_t* valueBegin, const uint8_t* end,
97                                                       const std::string& errLabel,
98                                                       ParseClient* parseClient) {
99     ssize_t signed_length = static_cast<ssize_t>(length);
100     if (end - valueBegin < signed_length || signed_length < 0) {
101         parseClient->error(hdrBegin, insufficientLengthString(length, end - valueBegin, errLabel));
102         return {hdrBegin, nullptr /* end parsing */};
103     }
104 
105     std::unique_ptr<Item> item = std::make_unique<T>(valueBegin, valueBegin + length);
106     return {valueBegin + length,
107             parseClient->item(item, hdrBegin, valueBegin, valueBegin + length)};
108 }
109 
110 class IncompleteItem {
111   public:
~IncompleteItem()112     virtual ~IncompleteItem() {}
113     virtual void add(std::unique_ptr<Item> item) = 0;
114 };
115 
116 class IncompleteArray : public Array, public IncompleteItem {
117   public:
IncompleteArray(size_t size)118     explicit IncompleteArray(size_t size) : mSize(size) {}
119 
120     // We return the "complete" size, rather than the actual size.
size() const121     size_t size() const override { return mSize; }
122 
add(std::unique_ptr<Item> item)123     void add(std::unique_ptr<Item> item) override {
124         mEntries.reserve(mSize);
125         mEntries.push_back(std::move(item));
126     }
127 
128   private:
129     size_t mSize;
130 };
131 
132 class IncompleteMap : public Map, public IncompleteItem {
133   public:
IncompleteMap(size_t size)134     explicit IncompleteMap(size_t size) : mSize(size) {}
135 
136     // We return the "complete" size, rather than the actual size.
size() const137     size_t size() const override { return mSize; }
138 
add(std::unique_ptr<Item> item)139     void add(std::unique_ptr<Item> item) override {
140         if (mKeyHeldForAdding) {
141             mEntries.reserve(mSize);
142             mEntries.push_back({std::move(mKeyHeldForAdding), std::move(item)});
143         } else {
144             mKeyHeldForAdding = std::move(item);
145         }
146     }
147 
148   private:
149     std::unique_ptr<Item> mKeyHeldForAdding;
150     size_t mSize;
151 };
152 
153 class IncompleteSemanticTag : public SemanticTag, public IncompleteItem {
154   public:
IncompleteSemanticTag(uint64_t value)155     explicit IncompleteSemanticTag(uint64_t value) : SemanticTag(value) {}
156 
157     // We return the "complete" size, rather than the actual size.
size() const158     size_t size() const override { return 1; }
159 
add(std::unique_ptr<Item> item)160     void add(std::unique_ptr<Item> item) override { mTaggedItem = std::move(item); }
161 };
162 
handleEntries(size_t entryCount,const uint8_t * hdrBegin,const uint8_t * pos,const uint8_t * end,const std::string & typeName,bool emitViews,ParseClient * parseClient)163 std::tuple<const uint8_t*, ParseClient*> handleEntries(size_t entryCount, const uint8_t* hdrBegin,
164                                                        const uint8_t* pos, const uint8_t* end,
165                                                        const std::string& typeName,
166                                                        bool emitViews,
167                                                        ParseClient* parseClient) {
168     while (entryCount > 0) {
169         --entryCount;
170         if (pos == end) {
171             parseClient->error(hdrBegin, "Not enough entries for " + typeName + ".");
172             return {hdrBegin, nullptr /* end parsing */};
173         }
174         std::tie(pos, parseClient) = parseRecursively(pos, end, emitViews, parseClient);
175         if (!parseClient) return {hdrBegin, nullptr};
176     }
177     return {pos, parseClient};
178 }
179 
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)180 std::tuple<const uint8_t*, ParseClient*> handleCompound(
181         std::unique_ptr<Item> item, uint64_t entryCount, const uint8_t* hdrBegin,
182         const uint8_t* valueBegin, const uint8_t* end, const std::string& typeName,
183         bool emitViews, ParseClient* parseClient) {
184     parseClient =
185             parseClient->item(item, hdrBegin, valueBegin, valueBegin /* don't know the end yet */);
186     if (!parseClient) return {hdrBegin, nullptr};
187 
188     const uint8_t* pos;
189     std::tie(pos, parseClient) =
190             handleEntries(entryCount, hdrBegin, valueBegin, end, typeName, emitViews, parseClient);
191     if (!parseClient) return {hdrBegin, nullptr};
192 
193     return {pos, parseClient->itemEnd(item, hdrBegin, valueBegin, pos)};
194 }
195 
parseRecursively(const uint8_t * begin,const uint8_t * end,bool emitViews,ParseClient * parseClient)196 std::tuple<const uint8_t*, ParseClient*> parseRecursively(const uint8_t* begin, const uint8_t* end,
197                                                           bool emitViews, ParseClient* parseClient) {
198     const uint8_t* pos = begin;
199 
200     MajorType type = static_cast<MajorType>(*pos & 0xE0);
201     uint8_t tagInt = *pos & 0x1F;
202     ++pos;
203 
204     bool success = true;
205     uint64_t addlData;
206     if (tagInt < ONE_BYTE_LENGTH) {
207         addlData = tagInt;
208     } else if (tagInt > EIGHT_BYTE_LENGTH) {
209         parseClient->error(
210                 begin,
211                 "Reserved additional information value or unsupported indefinite length item.");
212         return {begin, nullptr};
213     } else {
214         switch (tagInt) {
215             case ONE_BYTE_LENGTH:
216                 std::tie(success, addlData, pos) = parseLength<uint8_t>(pos, end, parseClient);
217                 break;
218 
219             case TWO_BYTE_LENGTH:
220                 std::tie(success, addlData, pos) = parseLength<uint16_t>(pos, end, parseClient);
221                 break;
222 
223             case FOUR_BYTE_LENGTH:
224                 std::tie(success, addlData, pos) = parseLength<uint32_t>(pos, end, parseClient);
225                 break;
226 
227             case EIGHT_BYTE_LENGTH:
228                 std::tie(success, addlData, pos) = parseLength<uint64_t>(pos, end, parseClient);
229                 break;
230 
231             default:
232                 CHECK(false);  //  It's impossible to get here
233                 break;
234         }
235     }
236 
237     if (!success) return {begin, nullptr};
238 
239     switch (type) {
240         case UINT:
241             return handleUint(addlData, begin, pos, parseClient);
242 
243         case NINT:
244             return handleNint(addlData, begin, pos, parseClient);
245 
246         case BSTR:
247             if (emitViews) {
248                 return handleString<ViewBstr>(addlData, begin, pos, end, "byte string", parseClient);
249             } else {
250                 return handleString<Bstr>(addlData, begin, pos, end, "byte string", parseClient);
251             }
252 
253         case TSTR:
254             if (emitViews) {
255                 return handleString<ViewTstr>(addlData, begin, pos, end, "text string", parseClient);
256             } else {
257                 return handleString<Tstr>(addlData, begin, pos, end, "text string", parseClient);
258             }
259 
260         case ARRAY:
261             return handleCompound(std::make_unique<IncompleteArray>(addlData), addlData, begin, pos,
262                                   end, "array", emitViews, parseClient);
263 
264         case MAP:
265             return handleCompound(std::make_unique<IncompleteMap>(addlData), addlData * 2, begin,
266                                   pos, end, "map", emitViews, parseClient);
267 
268         case SEMANTIC:
269             return handleCompound(std::make_unique<IncompleteSemanticTag>(addlData), 1, begin, pos,
270                                   end, "semantic", emitViews, parseClient);
271 
272         case SIMPLE:
273             switch (addlData) {
274                 case TRUE:
275                 case FALSE:
276                     return handleBool(addlData, begin, pos, parseClient);
277                 case NULL_V:
278                     return handleNull(begin, pos, parseClient);
279                 default:
280                     parseClient->error(begin, "Unsupported floating-point or simple value.");
281                     return {begin, nullptr};
282             }
283     }
284     CHECK(false);  // Impossible to get here.
285     return {};
286 }
287 
288 class FullParseClient : public ParseClient {
289   public:
item(std::unique_ptr<Item> & item,const uint8_t *,const uint8_t *,const uint8_t * end)290     virtual ParseClient* item(std::unique_ptr<Item>& item, const uint8_t*, const uint8_t*,
291                               const uint8_t* end) override {
292         if (mParentStack.empty() && !item->isCompound()) {
293             // This is the first and only item.
294             mTheItem = std::move(item);
295             mPosition = end;
296             return nullptr;  //  We're done.
297         }
298 
299         if (item->isCompound()) {
300             // Starting a new compound data item, i.e. a new parent.  Save it on the parent stack.
301             // It's safe to save a raw pointer because the unique_ptr is guaranteed to stay in
302             // existence until the corresponding itemEnd() call.
303             mParentStack.push(item.get());
304             return this;
305         } else {
306             appendToLastParent(std::move(item));
307             return this;
308         }
309     }
310 
itemEnd(std::unique_ptr<Item> & item,const uint8_t *,const uint8_t *,const uint8_t * end)311     virtual ParseClient* itemEnd(std::unique_ptr<Item>& item, const uint8_t*, const uint8_t*,
312                                  const uint8_t* end) override {
313         CHECK(item->isCompound() && item.get() == mParentStack.top());
314         mParentStack.pop();
315 
316         if (mParentStack.empty()) {
317             mTheItem = std::move(item);
318             mPosition = end;
319             return nullptr;  // We're done
320         } else {
321             appendToLastParent(std::move(item));
322             return this;
323         }
324     }
325 
error(const uint8_t * position,const std::string & errorMessage)326     virtual void error(const uint8_t* position, const std::string& errorMessage) override {
327         mPosition = position;
328         mErrorMessage = errorMessage;
329     }
330 
331     std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
332                std::string /* errMsg */>
parseResult()333     parseResult() {
334         std::unique_ptr<Item> p = std::move(mTheItem);
335         return {std::move(p), mPosition, std::move(mErrorMessage)};
336     }
337 
338   private:
appendToLastParent(std::unique_ptr<Item> item)339     void appendToLastParent(std::unique_ptr<Item> item) {
340         auto parent = mParentStack.top();
341 #if __has_feature(cxx_rtti)
342         assert(dynamic_cast<IncompleteItem*>(parent));
343 #endif
344 
345         IncompleteItem* parentItem{};
346         if (parent->type() == ARRAY) {
347             parentItem = static_cast<IncompleteArray*>(parent);
348         } else if (parent->type() == MAP) {
349             parentItem = static_cast<IncompleteMap*>(parent);
350         } else if (parent->asSemanticTag()) {
351             parentItem = static_cast<IncompleteSemanticTag*>(parent);
352         } else {
353             CHECK(false);  // Impossible to get here.
354         }
355         parentItem->add(std::move(item));
356     }
357 
358     std::unique_ptr<Item> mTheItem;
359     std::stack<Item*> mParentStack;
360     const uint8_t* mPosition = nullptr;
361     std::string mErrorMessage;
362 };
363 
364 }  // anonymous namespace
365 
parse(const uint8_t * begin,const uint8_t * end,ParseClient * parseClient)366 void parse(const uint8_t* begin, const uint8_t* end, ParseClient* parseClient) {
367     parseRecursively(begin, end, false, parseClient);
368 }
369 
370 std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
371            std::string /* errMsg */>
parse(const uint8_t * begin,const uint8_t * end)372 parse(const uint8_t* begin, const uint8_t* end) {
373     FullParseClient parseClient;
374     parse(begin, end, &parseClient);
375     return parseClient.parseResult();
376 }
377 
parseWithViews(const uint8_t * begin,const uint8_t * end,ParseClient * parseClient)378 void parseWithViews(const uint8_t* begin, const uint8_t* end, ParseClient* parseClient) {
379     parseRecursively(begin, end, true, parseClient);
380 }
381 
382 std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
383            std::string /* errMsg */>
parseWithViews(const uint8_t * begin,const uint8_t * end)384 parseWithViews(const uint8_t* begin, const uint8_t* end) {
385     FullParseClient parseClient;
386     parseWithViews(begin, end, &parseClient);
387     return parseClient.parseResult();
388 }
389 
390 }  // namespace cppbor
391