• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 The Android Open Source Project
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  *      http://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 "ProtoFuzzerUtils.h"
18 
19 #include <dirent.h>
20 #include <getopt.h>
21 #include <algorithm>
22 #include <sstream>
23 
24 #include "utils/InterfaceSpecUtil.h"
25 
26 using std::cerr;
27 using std::cout;
28 using std::string;
29 using std::unordered_map;
30 using std::vector;
31 
32 namespace android {
33 namespace vts {
34 namespace fuzzer {
35 
usage()36 static void usage() {
37   cout
38       << "Usage:\n"
39          "\n"
40          "./vts_proto_fuzzer <vts flags> -- <libfuzzer flags>\n"
41          "\n"
42          "VTS flags (strictly in form --flag=value):\n"
43          "\n"
44          "\tvts_binder_mode: if set, fuzzer will open the HAL in binder mode.\n"
45          "\tvts_exec_size: number of function calls per 1 run of "
46          "LLVMFuzzerTestOneInput.\n"
47          "\tvts_spec_dir: \":\"-separated list of directories on the target "
48          "containing .vts spec files.\n"
49          "\tvts_target_iface: name of interface targeted for fuzz, e.g. "
50          "\"INfc\".\n"
51          "\tvts_seed: optional integral argument used to initalize the random "
52          "number generator.\n"
53          "\n"
54          "libfuzzer flags (strictly in form -flag=value):\n"
55          "\tUse -help=1 to see libfuzzer flags\n"
56          "\n";
57 }
58 
59 static struct option long_options[] = {
60     {"help", no_argument, 0, 'h'},
61     {"vts_binder_mode", no_argument, 0, 'b'},
62     {"vts_spec_dir", required_argument, 0, 'd'},
63     {"vts_exec_size", required_argument, 0, 'e'},
64     {"vts_seed", required_argument, 0, 's'},
65     {"vts_target_iface", required_argument, 0, 't'}};
66 
67 // Removes information from CompSpec not needed by fuzzer.
TrimCompSpec(CompSpec * comp_spec)68 static void TrimCompSpec(CompSpec *comp_spec) {
69   if (comp_spec == nullptr) {
70     cerr << __func__ << ": empty CompSpec." << endl;
71     return;
72   }
73   if (comp_spec->has_interface()) {
74     auto *iface_spec = comp_spec->mutable_interface();
75     for (auto i = 0; i < iface_spec->api_size(); ++i) {
76       iface_spec->mutable_api(i)->clear_callflow();
77     }
78   }
79 }
80 
ExtractCompSpecs(string arg)81 static vector<CompSpec> ExtractCompSpecs(string arg) {
82   vector<CompSpec> result{};
83   string dir_path;
84   std::istringstream iss(arg);
85 
86   while (std::getline(iss, dir_path, ':')) {
87     DIR *dir;
88     struct dirent *ent;
89     if (!(dir = opendir(dir_path.c_str()))) {
90       cerr << "Could not open directory: " << dir_path << endl;
91       std::abort();
92     }
93     while ((ent = readdir(dir))) {
94       string vts_spec_name{ent->d_name};
95       if (vts_spec_name.find(".vts") != string::npos) {
96         string vts_spec_path = dir_path + "/" + vts_spec_name;
97         CompSpec comp_spec{};
98         ParseInterfaceSpec(vts_spec_path.c_str(), &comp_spec);
99         TrimCompSpec(&comp_spec);
100         result.emplace_back(std::move(comp_spec));
101       }
102     }
103   }
104   return result;
105 }
106 
ExtractPredefinedTypesFromVar(const TypeSpec & var_spec,unordered_map<string,TypeSpec> & predefined_types)107 static void ExtractPredefinedTypesFromVar(
108     const TypeSpec &var_spec,
109     unordered_map<string, TypeSpec> &predefined_types) {
110   predefined_types[var_spec.name()] = var_spec;
111   // Find all nested struct declarations.
112   for (const auto &sub_var_spec : var_spec.sub_struct()) {
113     ExtractPredefinedTypesFromVar(sub_var_spec, predefined_types);
114   }
115   // Find all nested union declarations.
116   for (const auto &sub_var_spec : var_spec.sub_union()) {
117     ExtractPredefinedTypesFromVar(sub_var_spec, predefined_types);
118   }
119 }
120 
ExtractProtoFuzzerParams(int argc,char ** argv)121 ProtoFuzzerParams ExtractProtoFuzzerParams(int argc, char **argv) {
122   ProtoFuzzerParams params;
123   int opt = 0;
124   int index = 0;
125   while ((opt = getopt_long_only(argc, argv, "", long_options, &index)) != -1) {
126     switch (opt) {
127       case 'h':
128         usage();
129         std::abort();
130       case 'b':
131         params.binder_mode_ = true;
132         break;
133       case 'd':
134         params.comp_specs_ = ExtractCompSpecs(optarg);
135         break;
136       case 'e':
137         params.exec_size_ = std::stoul(optarg);
138         break;
139       case 's':
140         params.seed_ = std::stoull(optarg);
141         break;
142       case 't':
143         params.target_iface_ = optarg;
144         break;
145       default:
146         // Ignore. This option will be handled by libfuzzer.
147         break;
148     }
149   }
150   return params;
151 }
152 
DebugString() const153 string ProtoFuzzerParams::DebugString() const {
154   std::stringstream ss;
155   ss << "Execution size: " << exec_size_ << endl;
156   ss << "Target interface: " << target_iface_ << endl;
157   ss << "Binder mode: " << binder_mode_ << endl;
158   ss << "Seed: " << seed_ << endl;
159   ss << "Loaded specs: " << endl;
160   for (const auto &spec : comp_specs_) {
161     ss << spec.component_name() << endl;
162   }
163   return ss.str();
164 }
165 
ExtractPredefinedTypes(const vector<CompSpec> & specs)166 unordered_map<string, TypeSpec> ExtractPredefinedTypes(
167     const vector<CompSpec> &specs) {
168   unordered_map<string, TypeSpec> predefined_types;
169   for (const auto &comp_spec : specs) {
170     for (const auto &var_spec : comp_spec.attribute()) {
171       ExtractPredefinedTypesFromVar(var_spec, predefined_types);
172     }
173     for (const auto &var_spec : comp_spec.interface().attribute()) {
174       ExtractPredefinedTypesFromVar(var_spec, predefined_types);
175     }
176   }
177   return predefined_types;
178 }
179 
FromArray(const uint8_t * data,size_t size,ExecSpec * exec_spec)180 bool FromArray(const uint8_t *data, size_t size, ExecSpec *exec_spec) {
181   // TODO(b/63136690): Use checksum to validate exec_spec more reliably.
182   return exec_spec->ParseFromArray(data, size) && exec_spec->has_valid() &&
183          exec_spec->valid();
184 }
185 
ToArray(uint8_t * data,size_t size,ExecSpec * exec_spec)186 size_t ToArray(uint8_t *data, size_t size, ExecSpec *exec_spec) {
187   exec_spec->set_valid(true);
188   size_t exec_size = exec_spec->ByteSize();
189   exec_spec->SerializeToArray(data, exec_size);
190   return exec_size;
191 }
192 
193 }  // namespace fuzzer
194 }  // namespace vts
195 }  // namespace android
196