1 /*
2  * Copyright (c) 2009-2022, Google LLC
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of Google LLC nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "upb/test/fuzz_util.h"
29 
30 #include "upb/message/message.h"
31 #include "upb/mini_table/decode.h"
32 #include "upb/mini_table/extension_internal.h"
33 #include "upb/mini_table/extension_registry.h"
34 #include "upb/upb.hpp"
35 
36 // Must be last
37 #include "upb/port/def.inc"
38 
39 namespace upb {
40 namespace fuzz {
41 
42 namespace {
43 
44 class Builder {
45  public:
Builder(const MiniTableFuzzInput & input,upb_Arena * arena)46   Builder(const MiniTableFuzzInput& input, upb_Arena* arena)
47       : input_(&input), arena_(arena) {}
48 
Build(upb_ExtensionRegistry ** exts)49   const upb_MiniTable* Build(upb_ExtensionRegistry** exts) {
50     BuildMessages();
51     BuildEnums();
52     BuildExtensions(exts);
53     if (!LinkMessages()) return nullptr;
54     return mini_tables_.empty() ? nullptr : mini_tables_.front();
55   }
56 
57  private:
58   void BuildMessages();
59   void BuildEnums();
60   void BuildExtensions(upb_ExtensionRegistry** exts);
61   bool LinkExtension(upb_MiniTableExtension* ext);
62   bool LinkMessages();
63 
NextLink()64   size_t NextLink() {
65     if (input_->links.empty()) return 0;
66     if (link_ == input_->links.size()) link_ = 0;
67     return input_->links[link_++];
68   }
69 
NextMiniTable()70   const upb_MiniTable* NextMiniTable() {
71     return mini_tables_.empty()
72                ? nullptr
73                : mini_tables_[NextLink() % mini_tables_.size()];
74   }
75 
NextEnumTable()76   const upb_MiniTableEnum* NextEnumTable() {
77     return enum_tables_.empty()
78                ? nullptr
79                : enum_tables_[NextLink() % enum_tables_.size()];
80   }
81 
82   const MiniTableFuzzInput* input_;
83   upb_Arena* arena_;
84   std::vector<const upb_MiniTable*> mini_tables_;
85   std::vector<const upb_MiniTableEnum*> enum_tables_;
86   size_t link_ = 0;
87 };
88 
BuildMessages()89 void Builder::BuildMessages() {
90   upb::Status status;
91   mini_tables_.reserve(input_->mini_descriptors.size());
92   for (const auto& d : input_->mini_descriptors) {
93     upb_MiniTable* table =
94         upb_MiniTable_Build(d.data(), d.size(), arena_, status.ptr());
95     if (table) mini_tables_.push_back(table);
96   }
97 }
98 
BuildEnums()99 void Builder::BuildEnums() {
100   upb::Status status;
101   enum_tables_.reserve(input_->enum_mini_descriptors.size());
102   for (const auto& d : input_->enum_mini_descriptors) {
103     upb_MiniTableEnum* enum_table =
104         upb_MiniTableEnum_Build(d.data(), d.size(), arena_, status.ptr());
105     if (enum_table) enum_tables_.push_back(enum_table);
106   }
107 }
108 
LinkExtension(upb_MiniTableExtension * ext)109 bool Builder::LinkExtension(upb_MiniTableExtension* ext) {
110   upb_MiniTableField* field = &ext->field;
111   if (upb_MiniTableField_CType(field) == kUpb_CType_Message) {
112     auto mt = NextMiniTable();
113     if (!mt) field->UPB_PRIVATE(descriptortype) = kUpb_FieldType_Int32;
114     ext->sub.submsg = mt;
115   }
116   if (upb_MiniTableField_IsClosedEnum(field)) {
117     auto et = NextEnumTable();
118     if (!et) field->UPB_PRIVATE(descriptortype) = kUpb_FieldType_Int32;
119     ext->sub.subenum = et;
120   }
121   return true;
122 }
123 
BuildExtensions(upb_ExtensionRegistry ** exts)124 void Builder::BuildExtensions(upb_ExtensionRegistry** exts) {
125   upb::Status status;
126   if (input_->extensions.empty()) {
127     *exts = nullptr;
128   } else {
129     *exts = upb_ExtensionRegistry_New(arena_);
130     const char* ptr = input_->extensions.data();
131     const char* end = ptr + input_->extensions.size();
132     // Iterate through the buffer, building extensions as long as we can.
133     while (ptr < end) {
134       upb_MiniTableExtension* ext = reinterpret_cast<upb_MiniTableExtension*>(
135           upb_Arena_Malloc(arena_, sizeof(*ext)));
136       upb_MiniTableSub sub;
137       const upb_MiniTable* extendee = NextMiniTable();
138       if (!extendee) break;
139       ptr = upb_MiniTableExtension_Init(ptr, end - ptr, ext, extendee, sub,
140                                         status.ptr());
141       if (!ptr) break;
142       if (!LinkExtension(ext)) continue;
143       if (upb_ExtensionRegistry_Lookup(*exts, ext->extendee, ext->field.number))
144         continue;
145       upb_ExtensionRegistry_AddArray(
146           *exts, const_cast<const upb_MiniTableExtension**>(&ext), 1);
147     }
148   }
149 }
150 
LinkMessages()151 bool Builder::LinkMessages() {
152   for (auto* t : mini_tables_) {
153     upb_MiniTable* table = const_cast<upb_MiniTable*>(t);
154     // For each field that requires a sub-table, assign one as appropriate.
155     for (size_t i = 0; i < table->field_count; i++) {
156       upb_MiniTableField* field =
157           const_cast<upb_MiniTableField*>(&table->fields[i]);
158       if (link_ == input_->links.size()) link_ = 0;
159       if (upb_MiniTableField_CType(field) == kUpb_CType_Message &&
160           !upb_MiniTable_SetSubMessage(table, field, NextMiniTable())) {
161         return false;
162       }
163       if (upb_MiniTableField_IsClosedEnum(field)) {
164         auto* et = NextEnumTable();
165         if (et) {
166           if (!upb_MiniTable_SetSubEnum(table, field, et)) return false;
167         } else {
168           // We don't have any sub-enums.  Override the field type so that it is
169           // not needed.
170           field->UPB_PRIVATE(descriptortype) = kUpb_FieldType_Int32;
171         }
172       }
173     }
174   }
175   return true;
176 }
177 
178 }  // namespace
179 
BuildMiniTable(const MiniTableFuzzInput & input,upb_ExtensionRegistry ** exts,upb_Arena * arena)180 const upb_MiniTable* BuildMiniTable(const MiniTableFuzzInput& input,
181                                     upb_ExtensionRegistry** exts,
182                                     upb_Arena* arena) {
183   Builder builder(input, arena);
184   return builder.Build(exts);
185 }
186 
187 }  // namespace fuzz
188 }  // namespace upb
189