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 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 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 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. 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 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 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 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 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. 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 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 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