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::cout; 27 using std::cerr; 28 using std::string; 29 using std::unordered_map; 30 using std::vector; 31 32 namespace android { 33 namespace vts { 34 namespace fuzzer { 35 36 static void usage() { 37 fprintf( 38 stdout, 39 "Usage:\n" 40 "\n" 41 "./vts_proto_fuzzer <vts flags> -- <libfuzzer flags>\n" 42 "\n" 43 "VTS flags (strictly in form --flag=value):\n" 44 "\n" 45 "\tvts_binder_mode: if set, fuzzer will open the HAL in binder mode.\n" 46 "\tvts_exec_size: number of function calls per 1 run of " 47 "LLVMFuzzerTestOneInput.\n" 48 "\tvts_spec_dir: \":\"-separated list of directories on the target " 49 "containing .vts spec files.\n" 50 "\tvts_target_iface: name of interface targeted for fuzz, e.g. " 51 "\"INfc\".\n" 52 "\n" 53 "libfuzzer flags (strictly in form -flag=value):\n" 54 "\tUse -help=1 to see libfuzzer flags\n" 55 "\n"); 56 } 57 58 static struct option long_options[] = { 59 {"help", no_argument, 0, 'h'}, 60 {"vts_binder_mode", no_argument, 0, 'b'}, 61 {"vts_spec_dir", required_argument, 0, 'd'}, 62 {"vts_exec_size", required_argument, 0, 'e'}, 63 {"vts_target_iface", required_argument, 0, 't'}}; 64 65 // Removes information from CompSpec not needed by fuzzer. 66 static void TrimCompSpec(CompSpec *comp_spec) { 67 if (comp_spec == nullptr) { 68 cerr << __func__ << ": empty CompSpec." << endl; 69 return; 70 } 71 if (comp_spec->has_interface()) { 72 auto *iface_spec = comp_spec->mutable_interface(); 73 for (auto i = 0; i < iface_spec->api_size(); ++i) { 74 iface_spec->mutable_api(i)->clear_callflow(); 75 } 76 } 77 } 78 79 static vector<CompSpec> ExtractCompSpecs(string arg) { 80 vector<CompSpec> result{}; 81 string dir_path; 82 std::istringstream iss(arg); 83 84 while (std::getline(iss, dir_path, ':')) { 85 DIR *dir; 86 struct dirent *ent; 87 if (!(dir = opendir(dir_path.c_str()))) { 88 cerr << "Could not open directory: " << dir_path << endl; 89 exit(1); 90 } 91 while ((ent = readdir(dir))) { 92 string vts_spec_name{ent->d_name}; 93 if (vts_spec_name.find(".vts") != string::npos) { 94 cout << "Loading: " << vts_spec_name << endl; 95 string vts_spec_path = dir_path + "/" + vts_spec_name; 96 CompSpec comp_spec{}; 97 ParseInterfaceSpec(vts_spec_path.c_str(), &comp_spec); 98 TrimCompSpec(&comp_spec); 99 result.emplace_back(std::move(comp_spec)); 100 } 101 } 102 } 103 return result; 104 } 105 106 static void ExtractPredefinedTypesFromVar( 107 const TypeSpec &var_spec, 108 unordered_map<string, TypeSpec> &predefined_types) { 109 predefined_types[var_spec.name()] = var_spec; 110 for (const auto &sub_var_spec : var_spec.sub_struct()) { 111 ExtractPredefinedTypesFromVar(sub_var_spec, predefined_types); 112 } 113 } 114 115 ProtoFuzzerParams ExtractProtoFuzzerParams(int argc, char **argv) { 116 ProtoFuzzerParams params; 117 int opt = 0; 118 int index = 0; 119 while ((opt = getopt_long_only(argc, argv, "", long_options, &index)) != -1) { 120 switch (opt) { 121 case 'h': 122 usage(); 123 exit(0); 124 case 'b': 125 params.binder_mode_ = true; 126 break; 127 case 'd': 128 params.comp_specs_ = ExtractCompSpecs(optarg); 129 break; 130 case 'e': 131 params.exec_size_ = atoi(optarg); 132 break; 133 case 't': 134 params.target_iface_ = optarg; 135 break; 136 default: 137 // Ignore. This option will be handled by libfuzzer. 138 break; 139 } 140 } 141 return params; 142 } 143 144 unordered_map<string, TypeSpec> ExtractPredefinedTypes( 145 const vector<CompSpec> &specs) { 146 unordered_map<string, TypeSpec> predefined_types; 147 for (const auto &comp_spec : specs) { 148 for (const auto &var_spec : comp_spec.attribute()) { 149 ExtractPredefinedTypesFromVar(var_spec, predefined_types); 150 } 151 for (const auto &var_spec : comp_spec.interface().attribute()) { 152 ExtractPredefinedTypesFromVar(var_spec, predefined_types); 153 } 154 } 155 return predefined_types; 156 } 157 158 bool FromArray(const uint8_t *data, size_t size, ExecSpec *exec_spec) { 159 // TODO(b/63136690): Use checksum to validate exec_spec more reliably. 160 return exec_spec->ParseFromArray(data, size) && exec_spec->has_valid() && 161 exec_spec->valid(); 162 } 163 164 size_t ToArray(uint8_t *data, size_t size, ExecSpec *exec_spec) { 165 exec_spec->set_valid(true); 166 size_t exec_size = exec_spec->ByteSize(); 167 exec_spec->SerializeToArray(data, exec_size); 168 return exec_size; 169 } 170 171 } // namespace fuzzer 172 } // namespace vts 173 } // namespace android 174