Home | History | Annotate | Download | only in iface_fuzzer
      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