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