blob: b9a56353bc0491ed99e12671018f9f0b40a21778 [file] [log] [blame]
Tri Vo77e0ca02016-12-05 10:08:59 -08001/*
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
Tri Vo16eed232017-03-08 08:52:15 -080019#include <dirent.h>
Tri Vo16eed232017-03-08 08:52:15 -080020#include <getopt.h>
21#include <algorithm>
Tri Vo826a2012017-01-05 12:21:25 -080022#include <sstream>
23
Tri Vo826a2012017-01-05 12:21:25 -080024#include "utils/InterfaceSpecUtil.h"
25
Tri Vo77e0ca02016-12-05 10:08:59 -080026using std::cerr;
Tri Vo99bf6bd2017-07-20 16:07:34 -070027using std::cout;
Tri Vo77e0ca02016-12-05 10:08:59 -080028using std::string;
29using std::unordered_map;
30using std::vector;
31
Tri Vo16eed232017-03-08 08:52:15 -080032namespace android {
33namespace vts {
Tri Vo70c1ab62017-03-15 09:19:10 -070034namespace fuzzer {
Tri Vo16eed232017-03-08 08:52:15 -080035
Tri Vo826a2012017-01-05 12:21:25 -080036static void usage() {
Tri Vo99bf6bd2017-07-20 16:07:34 -070037 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"
Tri Vo624961d2017-07-24 10:30:41 -070051 "\tvts_seed: optional integral argument used to initalize the random "
52 "number generator.\n"
Tri Vo99bf6bd2017-07-20 16:07:34 -070053 "\n"
54 "libfuzzer flags (strictly in form -flag=value):\n"
55 "\tUse -help=1 to see libfuzzer flags\n"
56 "\n";
Tri Vo826a2012017-01-05 12:21:25 -080057}
58
59static struct option long_options[] = {
60 {"help", no_argument, 0, 'h'},
Tri Vof4037d42017-03-31 17:28:25 -070061 {"vts_binder_mode", no_argument, 0, 'b'},
Tri Vo16eed232017-03-08 08:52:15 -080062 {"vts_spec_dir", required_argument, 0, 'd'},
63 {"vts_exec_size", required_argument, 0, 'e'},
Tri Vo624961d2017-07-24 10:30:41 -070064 {"vts_seed", required_argument, 0, 's'},
Tri Vo16eed232017-03-08 08:52:15 -080065 {"vts_target_iface", required_argument, 0, 't'}};
Tri Vo77e0ca02016-12-05 10:08:59 -080066
Tri Vo70c1ab62017-03-15 09:19:10 -070067// Removes information from CompSpec not needed by fuzzer.
68static 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
Tri Vo487a1f32017-04-14 12:30:59 -070081static vector<CompSpec> ExtractCompSpecs(string arg) {
Tri Vo70c1ab62017-03-15 09:19:10 -070082 vector<CompSpec> result{};
Tri Vo487a1f32017-04-14 12:30:59 -070083 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;
Tri Vo4fb63ba2017-07-20 15:36:48 -070091 std::abort();
Tri Vo487a1f32017-04-14 12:30:59 -070092 }
93 while ((ent = readdir(dir))) {
94 string vts_spec_name{ent->d_name};
95 if (vts_spec_name.find(".vts") != string::npos) {
Tri Vo487a1f32017-04-14 12:30:59 -070096 string vts_spec_path = dir_path + "/" + vts_spec_name;
97 CompSpec comp_spec{};
Zhuoyao Zhang6af0bde2017-06-23 15:10:42 -070098 ParseInterfaceSpec(vts_spec_path.c_str(), &comp_spec);
Tri Vo487a1f32017-04-14 12:30:59 -070099 TrimCompSpec(&comp_spec);
100 result.emplace_back(std::move(comp_spec));
101 }
Tri Vo16eed232017-03-08 08:52:15 -0800102 }
103 }
104 return result;
105}
Tri Vo826a2012017-01-05 12:21:25 -0800106
Tri Vo16eed232017-03-08 08:52:15 -0800107static void ExtractPredefinedTypesFromVar(
Tri Vo70c1ab62017-03-15 09:19:10 -0700108 const TypeSpec &var_spec,
109 unordered_map<string, TypeSpec> &predefined_types) {
Tri Vo16eed232017-03-08 08:52:15 -0800110 predefined_types[var_spec.name()] = var_spec;
Tri Vo4d74ef12017-08-15 17:47:14 -0700111 // Find all nested struct declarations.
Tri Vo16eed232017-03-08 08:52:15 -0800112 for (const auto &sub_var_spec : var_spec.sub_struct()) {
113 ExtractPredefinedTypesFromVar(sub_var_spec, predefined_types);
114 }
Tri Vo4d74ef12017-08-15 17:47:14 -0700115 // Find all nested union declarations.
116 for (const auto &sub_var_spec : var_spec.sub_union()) {
117 ExtractPredefinedTypesFromVar(sub_var_spec, predefined_types);
118 }
Tri Vo826a2012017-01-05 12:21:25 -0800119}
120
121ProtoFuzzerParams 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();
Tri Vo4fb63ba2017-07-20 15:36:48 -0700129 std::abort();
Tri Vof4037d42017-03-31 17:28:25 -0700130 case 'b':
Tri Vo28dbc3d2017-04-19 14:47:09 -0700131 params.binder_mode_ = true;
Tri Vof4037d42017-03-31 17:28:25 -0700132 break;
Tri Vo16eed232017-03-08 08:52:15 -0800133 case 'd':
Tri Vo826a2012017-01-05 12:21:25 -0800134 params.comp_specs_ = ExtractCompSpecs(optarg);
135 break;
136 case 'e':
Tri Vo2beb2e72017-07-27 16:54:03 -0700137 params.exec_size_ = std::stoul(optarg);
Tri Vo624961d2017-07-24 10:30:41 -0700138 break;
139 case 's':
Tri Vo2beb2e72017-07-27 16:54:03 -0700140 params.seed_ = std::stoull(optarg);
Tri Vo826a2012017-01-05 12:21:25 -0800141 break;
Tri Vo16eed232017-03-08 08:52:15 -0800142 case 't':
143 params.target_iface_ = optarg;
144 break;
Tri Vo826a2012017-01-05 12:21:25 -0800145 default:
146 // Ignore. This option will be handled by libfuzzer.
147 break;
148 }
149 }
150 return params;
151}
152
Tri Vof657d672017-07-26 16:13:02 -0700153string ProtoFuzzerParams::DebugString() const {
Tri Vo624961d2017-07-24 10:30:41 -0700154 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
Tri Vo70c1ab62017-03-15 09:19:10 -0700166unordered_map<string, TypeSpec> ExtractPredefinedTypes(
167 const vector<CompSpec> &specs) {
168 unordered_map<string, TypeSpec> predefined_types;
Tri Vo77e0ca02016-12-05 10:08:59 -0800169 for (const auto &comp_spec : specs) {
170 for (const auto &var_spec : comp_spec.attribute()) {
Tri Voafcb0242017-01-17 16:11:01 -0800171 ExtractPredefinedTypesFromVar(var_spec, predefined_types);
Tri Vo77e0ca02016-12-05 10:08:59 -0800172 }
Tri Vo69d71b32017-04-12 18:24:50 -0700173 for (const auto &var_spec : comp_spec.interface().attribute()) {
174 ExtractPredefinedTypesFromVar(var_spec, predefined_types);
175 }
Tri Vo77e0ca02016-12-05 10:08:59 -0800176 }
177 return predefined_types;
178}
179
Tri Vodfe95ea2017-06-07 17:52:10 -0700180bool 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
186size_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
Tri Vo70c1ab62017-03-15 09:19:10 -0700193} // namespace fuzzer
Tri Vo77e0ca02016-12-05 10:08:59 -0800194} // namespace vts
195} // namespace android