• 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 <dlfcn.h>
21 #include <getopt.h>
22 #include <algorithm>
23 #include <sstream>
24 
25 #include "specification_parser/InterfaceSpecificationParser.h"
26 #include "utils/InterfaceSpecUtil.h"
27 
28 using std::cout;
29 using std::cerr;
30 using std::string;
31 using std::unordered_map;
32 using std::vector;
33 
34 namespace android {
35 namespace vts {
36 namespace fuzzer {
37 
usage()38 static void usage() {
39   fprintf(
40       stdout,
41       "Usage:\n"
42       "\n"
43       "./<fuzzer> <vts flags> -- <libfuzzer flags>\n"
44       "\n"
45       "VTS flags (strictly in form --flag=value):\n"
46       "\n"
47       " vts_spec_files \tColumn-separated list of paths to vts spec files.\n"
48       " vts_exec_size \t\tNumber of function calls per fuzzer execution.\n"
49       "\n"
50       "libfuzzer flags (strictly in form -flag=value):\n"
51       " Use -help=1 to see libfuzzer flags\n"
52       "\n");
53 }
54 
55 static struct option long_options[] = {
56     {"help", no_argument, 0, 'h'},
57     {"vts_binder_mode", no_argument, 0, 'b'},
58     {"vts_spec_dir", required_argument, 0, 'd'},
59     {"vts_exec_size", required_argument, 0, 'e'},
60     {"vts_service_name", required_argument, 0, 's'},
61     {"vts_target_iface", required_argument, 0, 't'}};
62 
GetDriverName(const CompSpec & comp_spec)63 static string GetDriverName(const CompSpec &comp_spec) {
64   stringstream version;
65   version.precision(1);
66   version << fixed << comp_spec.component_type_version();
67   string driver_name =
68       comp_spec.package() + "@" + version.str() + "-vts.driver.so";
69   return driver_name;
70 }
71 
GetServiceName(const CompSpec & comp_spec)72 static string GetServiceName(const CompSpec &comp_spec) {
73   // Infer HAL service name from its package name.
74   string prefix = "android.hardware.";
75   string service_name = comp_spec.package().substr(prefix.size());
76   return service_name;
77 }
78 
79 // Removes information from CompSpec not needed by fuzzer.
TrimCompSpec(CompSpec * comp_spec)80 static void TrimCompSpec(CompSpec *comp_spec) {
81   if (comp_spec == nullptr) {
82     cerr << __func__ << ": empty CompSpec." << endl;
83     return;
84   }
85   if (comp_spec->has_interface()) {
86     auto *iface_spec = comp_spec->mutable_interface();
87     for (auto i = 0; i < iface_spec->api_size(); ++i) {
88       iface_spec->mutable_api(i)->clear_callflow();
89     }
90   }
91 }
92 
ExtractCompSpecs(string dir_path)93 static vector<CompSpec> ExtractCompSpecs(string dir_path) {
94   vector<CompSpec> result{};
95   DIR *dir;
96   struct dirent *ent;
97   if (!(dir = opendir(dir_path.c_str()))) {
98     cerr << "Could not open directory: " << dir_path << endl;
99     exit(1);
100   }
101   while ((ent = readdir(dir))) {
102     string vts_spec_name{ent->d_name};
103     if (vts_spec_name.find(".vts") != string::npos) {
104       string vts_spec_path = dir_path + "/" + vts_spec_name;
105       CompSpec comp_spec{};
106       InterfaceSpecificationParser::parse(vts_spec_path.c_str(), &comp_spec);
107       TrimCompSpec(&comp_spec);
108       result.emplace_back(std::move(comp_spec));
109     }
110   }
111   return result;
112 }
113 
ExtractPredefinedTypesFromVar(const TypeSpec & var_spec,unordered_map<string,TypeSpec> & predefined_types)114 static void ExtractPredefinedTypesFromVar(
115     const TypeSpec &var_spec,
116     unordered_map<string, TypeSpec> &predefined_types) {
117   predefined_types[var_spec.name()] = var_spec;
118   for (const auto &sub_var_spec : var_spec.sub_struct()) {
119     ExtractPredefinedTypesFromVar(sub_var_spec, predefined_types);
120   }
121 }
122 
ExtractProtoFuzzerParams(int argc,char ** argv)123 ProtoFuzzerParams ExtractProtoFuzzerParams(int argc, char **argv) {
124   ProtoFuzzerParams params;
125   int opt = 0;
126   int index = 0;
127   while ((opt = getopt_long_only(argc, argv, "", long_options, &index)) != -1) {
128     switch (opt) {
129       case 'h':
130         usage();
131         exit(0);
132       case 'b':
133         params.get_stub_ = false;
134         break;
135       case 'd':
136         params.comp_specs_ = ExtractCompSpecs(optarg);
137         break;
138       case 'e':
139         params.exec_size_ = atoi(optarg);
140         break;
141       case 's':
142         params.service_name_ = optarg;
143         break;
144       case 't':
145         params.target_iface_ = optarg;
146         break;
147       default:
148         // Ignore. This option will be handled by libfuzzer.
149         break;
150     }
151   }
152   return params;
153 }
154 
FindTargetCompSpec(const vector<CompSpec> & specs,const string & target_iface)155 CompSpec FindTargetCompSpec(const vector<CompSpec> &specs,
156                             const string &target_iface) {
157   if (target_iface.empty()) {
158     cerr << "Target interface not specified." << endl;
159     exit(1);
160   }
161   auto spec = std::find_if(specs.begin(), specs.end(), [target_iface](auto x) {
162     return x.component_name().compare(target_iface) == 0;
163   });
164   if (spec == specs.end()) {
165     cerr << "Target interface doesn't match any of the loaded .vts files."
166          << endl;
167     exit(1);
168   }
169   return *spec;
170 }
171 
172 // TODO(trong): this should be done using FuzzerWrapper.
InitHalDriver(const CompSpec & comp_spec,string service_name,bool get_stub)173 FuzzerBase *InitHalDriver(const CompSpec &comp_spec, string service_name,
174                           bool get_stub) {
175   const char *error;
176   string driver_name = GetDriverName(comp_spec);
177   void *handle = dlopen(driver_name.c_str(), RTLD_LAZY);
178   if (!handle) {
179     cerr << __func__ << ": " << dlerror() << endl;
180     cerr << __func__ << ": Can't load shared library: " << driver_name << endl;
181     exit(-1);
182   }
183 
184   // Clear dlerror().
185   dlerror();
186   string function_name = GetFunctionNamePrefix(comp_spec);
187   using loader_func = FuzzerBase *(*)();
188   auto hal_loader = (loader_func)dlsym(handle, function_name.c_str());
189   if ((error = dlerror()) != NULL) {
190     cerr << __func__ << ": Can't find: " << function_name << endl;
191     cerr << error << endl;
192     exit(1);
193   }
194 
195   FuzzerBase *hal = hal_loader();
196   // For fuzzing, only passthrough mode provides coverage.
197   if (get_stub) {
198     cout << "HAL used in passthrough mode." << endl;
199   } else {
200     cout << "HAL used in binderized mode." << endl;
201   }
202   if (!hal->GetService(get_stub, service_name.c_str())) {
203     cerr << __func__ << ": GetService(true, " << service_name << ") failed."
204          << endl;
205     exit(1);
206   }
207   return hal;
208 }
209 
ExtractPredefinedTypes(const vector<CompSpec> & specs)210 unordered_map<string, TypeSpec> ExtractPredefinedTypes(
211     const vector<CompSpec> &specs) {
212   unordered_map<string, TypeSpec> predefined_types;
213   for (const auto &comp_spec : specs) {
214     for (const auto &var_spec : comp_spec.attribute()) {
215       ExtractPredefinedTypesFromVar(var_spec, predefined_types);
216     }
217   }
218   return predefined_types;
219 }
220 
Execute(FuzzerBase * hal,const ExecSpec & exec_spec)221 void Execute(FuzzerBase *hal, const ExecSpec &exec_spec) {
222   FuncSpec result{};
223   for (const auto &func_spec : exec_spec.api()) {
224     hal->CallFunction(func_spec, "", &result);
225   }
226 }
227 
228 }  // namespace fuzzer
229 }  // namespace vts
230 }  // namespace android
231