1 /*
2  * Copyright 2017 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 "ProtoFuzzerRunner.h"
18 
19 #include <dlfcn.h>
20 #include <sstream>
21 
22 #include "utils/InterfaceSpecUtil.h"
23 #include "vintf/HalManifest.h"
24 #include "vintf/Version.h"
25 #include "vintf/VintfObject.h"
26 
27 using android::vintf::HalManifest;
28 using android::vintf::Version;
29 
30 using std::cerr;
31 using std::cout;
32 using std::string;
33 using std::unordered_map;
34 using std::vector;
35 
36 namespace android {
37 namespace vts {
38 namespace fuzzer {
39 
GetVersionString(const CompSpec & comp_spec)40 static string GetVersionString(const CompSpec &comp_spec) {
41   stringstream version_major, version_minor;
42   version_major << comp_spec.component_type_version_major();
43   version_minor << comp_spec.component_type_version_minor();
44   return version_major.str() + "." + version_minor.str();
45 }
46 
GetDriverName(const CompSpec & comp_spec)47 static string GetDriverName(const CompSpec &comp_spec) {
48   string version_string = GetVersionString(comp_spec);
49   string driver_name =
50       comp_spec.package() + "@" + version_string + "-vts.driver.so";
51   return driver_name;
52 }
53 
GetServiceName(const CompSpec & comp_spec)54 static string GetServiceName(const CompSpec &comp_spec) {
55   string hal_name = comp_spec.package();
56   string iface_name = comp_spec.component_name();
57 
58   auto instance_names =
59       ::android::vintf::VintfObject::GetDeviceHalManifest()->getHidlInstances(
60           hal_name,
61           Version(comp_spec.component_type_version_major(),
62                   comp_spec.component_type_version_minor()),
63           iface_name);
64   if (instance_names.empty()) {
65     cerr << "HAL service name not available in VINTF." << endl;
66     std::abort();
67   }
68 
69   // For fuzzing we don't care which instance of the HAL is targeted.
70   string service_name = *instance_names.begin();
71   cout << "Available HAL instances: " << endl;
72   for (const string &instance_name : instance_names) {
73     cout << instance_name << endl;
74   }
75   cout << "Using HAL instance: " << service_name << endl;
76 
77   return service_name;
78 }
79 
Dlopen(string lib_name)80 static void *Dlopen(string lib_name) {
81   // Clear dlerror().
82   dlerror();
83   void *handle = dlopen(lib_name.c_str(), RTLD_LAZY);
84   if (!handle) {
85     cerr << __func__ << ": " << dlerror() << endl;
86     cerr << __func__ << ": Can't load shared library: " << lib_name << endl;
87     std::abort();
88   }
89   return handle;
90 }
91 
Dlsym(void * handle,string function_name)92 static void *Dlsym(void *handle, string function_name) {
93   const char *error;
94   // Clear dlerror().
95   dlerror();
96   void *function = dlsym(handle, function_name.c_str());
97   if ((error = dlerror()) != NULL) {
98     cerr << __func__ << ": Can't find: " << function_name << endl;
99     cerr << error << endl;
100     std::abort();
101   }
102   return function;
103 }
104 
GetService(DriverBase * hal,string service_name,bool binder_mode)105 static void GetService(DriverBase *hal, string service_name, bool binder_mode) {
106   // For fuzzing, only passthrough mode provides coverage.
107   // If binder mode is not requested, attempt to open HAL in passthrough mode.
108   // If the attempt fails, fall back to binder mode.
109   if (!binder_mode) {
110     if (!hal->GetService(true, service_name.c_str())) {
111       cerr << __func__ << ": Failed to open HAL in passthrough mode. "
112            << "Falling back to binder mode." << endl;
113     } else {
114       cerr << "HAL opened in passthrough mode." << endl;
115       return;
116     }
117   }
118 
119   if (!hal->GetService(false, service_name.c_str())) {
120     cerr << __func__ << ": Failed to open HAL in binder mode." << endl;
121     std::abort();
122   } else {
123     cerr << "HAL opened in binder mode." << endl;
124     return;
125   }
126 }
127 
LoadInterface(const CompSpec & comp_spec,uint64_t hidl_service=0)128 DriverBase *ProtoFuzzerRunner::LoadInterface(const CompSpec &comp_spec,
129                                              uint64_t hidl_service = 0) {
130   DriverBase *hal;
131   // Clear dlerror().
132   dlerror();
133 
134   // DriverBase can be constructed with or without an argument.
135   // Using different DriverBase constructors requires dlsym'ing different
136   // symbols from the driver library.
137   string function_name = GetFunctionNamePrefix(comp_spec);
138   if (hidl_service) {
139     function_name += "with_arg";
140     using loader_func = DriverBase *(*)(uint64_t);
141     auto hal_loader = (loader_func)Dlsym(driver_handle_, function_name.c_str());
142     hal = hal_loader(hidl_service);
143   } else {
144     using loader_func = DriverBase *(*)();
145     auto hal_loader = (loader_func)Dlsym(driver_handle_, function_name.c_str());
146     hal = hal_loader();
147   }
148   return hal;
149 }
150 
ProtoFuzzerRunner(const vector<CompSpec> & comp_specs,const string version_iface)151 ProtoFuzzerRunner::ProtoFuzzerRunner(const vector<CompSpec> &comp_specs,
152                                      const string version_iface) {
153   for (const auto &comp_spec : comp_specs) {
154     string target_version = GetVersionString(comp_spec);
155     if (comp_spec.has_interface() && target_version == version_iface) {
156       string name = comp_spec.component_name();
157       comp_specs_[name] = comp_spec;
158     }
159   }
160 }
161 
Init(const string & iface_name,bool binder_mode)162 void ProtoFuzzerRunner::Init(const string &iface_name, bool binder_mode) {
163   const CompSpec *comp_spec = FindCompSpec(iface_name);
164   // dlopen VTS driver library.
165   string driver_name = GetDriverName(*comp_spec);
166   driver_handle_ = Dlopen(driver_name);
167 
168   std::shared_ptr<DriverBase> hal{LoadInterface(*comp_spec)};
169   string service_name = GetServiceName(*comp_spec);
170   cerr << "HAL name: " << comp_spec->package() << endl
171        << "Interface name: " << comp_spec->component_name() << endl
172        << "Service name: " << service_name << endl;
173 
174   // This should only be done for top-level interfaces.
175   GetService(hal.get(), service_name, binder_mode);
176 
177   // Register this interface as opened by the runner.
178   opened_ifaces_[iface_name] = {
179       .comp_spec_ = comp_spec, .hal_ = hal,
180   };
181 }
182 
Execute(const ExecSpec & exec_spec)183 void ProtoFuzzerRunner::Execute(const ExecSpec &exec_spec) {
184   for (const auto &func_call : exec_spec.function_call()) {
185     Execute(func_call);
186   }
187 }
188 
Execute(const FuncCall & func_call)189 void ProtoFuzzerRunner::Execute(const FuncCall &func_call) {
190   string iface_name = func_call.hidl_interface_name();
191   const FuncSpec &func_spec = func_call.api();
192 
193   auto iface_desc = opened_ifaces_.find(iface_name);
194   if (iface_desc == opened_ifaces_.end()) {
195     cerr << "Interface is not open: " << iface_name << endl;
196     std::abort();
197   }
198 
199   FuncSpec result{};
200   iface_desc->second.hal_->CallFunction(func_spec, "", &result);
201 
202   stats_.RegisterTouch(iface_name, func_spec.name());
203   ProcessReturnValue(result);
204 }
205 
StripNamespace(const string & type)206 static string StripNamespace(const string &type) {
207   size_t idx = type.find_last_of(':');
208   if (idx == string::npos) {
209     return "";
210   }
211   return type.substr(idx + 1);
212 }
213 
ProcessReturnValue(const FuncSpec & result)214 void ProtoFuzzerRunner::ProcessReturnValue(const FuncSpec &result) {
215   for (const auto &var : result.return_type_hidl()) {
216     // If result contains a pointer to an interface, register it in
217     // opened_ifaces_ table. That pointer must not be a nullptr.
218     if (var.has_hidl_interface_pointer() && var.hidl_interface_pointer() &&
219         var.has_predefined_type()) {
220       uint64_t hidl_service = var.hidl_interface_pointer();
221       string type = var.predefined_type();
222       string iface_name = StripNamespace(type);
223 
224       const CompSpec *comp_spec = FindCompSpec(iface_name);
225       std::shared_ptr<DriverBase> hal{LoadInterface(*comp_spec, hidl_service)};
226 
227       // If this interface has not been seen before, record the fact.
228       if (opened_ifaces_.find(iface_name) == opened_ifaces_.end()) {
229         cerr << "Discovered new interface: " << iface_name << endl;
230       }
231 
232       // Register this interface as opened by the runner.
233       opened_ifaces_[iface_name] = {
234           .comp_spec_ = comp_spec, .hal_ = hal,
235       };
236     }
237   }
238 }
239 
FindCompSpec(std::string name)240 const CompSpec *ProtoFuzzerRunner::FindCompSpec(std::string name) {
241   auto comp_spec = comp_specs_.find(name);
242   if (comp_spec == comp_specs_.end()) {
243     cerr << "VTS spec not found: " << name << endl;
244     std::abort();
245   }
246   return &comp_spec->second;
247 }
248 
249 }  // namespace fuzzer
250 }  // namespace vts
251 }  // namespace android
252