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