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