| /* |
| * Copyright 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "fuzz_tester/FuzzerBase.h" |
| |
| #include <dirent.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <sys/mman.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| #include <fstream> |
| #include <iostream> |
| #include <sstream> |
| #include <string> |
| #include <vector> |
| |
| #include "test/vts/proto/InterfaceSpecificationMessage.pb.h" |
| |
| #include "component_loader/DllLoader.h" |
| #include "utils/InterfaceSpecUtil.h" |
| |
| #include "gcda_parser.h" |
| |
| using namespace std; |
| using namespace android; |
| |
| #define USE_GCOV 1 |
| |
| #if SANCOV |
| extern "C" { |
| typedef unsigned long uptr; |
| |
| #define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default"))) |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __sanitizer_cov(uint32_t* guard) { |
| printf("sancov\n"); |
| coverage_data.Add(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()), |
| guard); |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void* __asan_memset(void* block, int c, uptr size) { |
| ASAN_MEMSET_IMPL(nullptr, block, c, size); |
| return block; |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_register_globals() {} |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_unregister_globals() {} |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_handle_no_return() {} |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_report_load1() {} |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_report_load2() {} |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_report_load4() {} |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_report_load8() {} |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_report_load16() {} |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_report_store1() {} |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_report_store2() {} |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_report_store4() {} |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_report_store8() {} |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_report_store16() {} |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_set_error_report_callback() {} |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| uptr __asan_stack_malloc_1(uptr size, uptr real_stack) { |
| return (uptr)malloc(size); |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| uptr __asan_stack_malloc_2(uptr size, uptr real_stack) { |
| return (uptr)malloc(size); |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| uptr __asan_stack_malloc_3(uptr size, uptr real_stack) { |
| return (uptr)malloc(size); |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| uptr __asan_stack_malloc_4(uptr size, uptr real_stack) { |
| return (uptr)malloc(size); |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| uptr __asan_stack_malloc_5(uptr size, uptr real_stack) { |
| return (uptr)malloc(size); |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| uptr __asan_stack_malloc_6(uptr size, uptr real_stack) { |
| return (uptr)malloc(size); |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| uptr __asan_stack_malloc_7(uptr size, uptr real_stack) { |
| return (uptr)malloc(size); |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| uptr __asan_stack_malloc_8(uptr size, uptr real_stack) { |
| return (uptr)malloc(size); |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| uptr __asan_stack_malloc_9(uptr size, uptr real_stack) { |
| return (uptr)malloc(size); |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| uptr __asan_stack_malloc_10(uptr size, uptr real_stack) { |
| return (uptr)malloc(size); |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_stack_free_1(uptr ptr, uptr size, uptr real_stack) { |
| free((void*)ptr); |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_stack_free_2(uptr ptr, uptr size, uptr real_stack) { |
| free((void*)ptr); |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_stack_free_3(uptr ptr, uptr size, uptr real_stack) { |
| free((void*)ptr); |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_stack_free_4(uptr ptr, uptr size, uptr real_stack) { |
| free((void*)ptr); |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_stack_free_5(uptr ptr, uptr size, uptr real_stack) { |
| free((void*)ptr); |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_stack_free_6(uptr ptr, uptr size, uptr real_stack) { |
| free((void*)ptr); |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_stack_free_7(uptr ptr, uptr size, uptr real_stack) { |
| free((void*)ptr); |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_stack_free_8(uptr ptr, uptr size, uptr real_stack) { |
| free((void*)ptr); |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_stack_free_9(uptr ptr, uptr size, uptr real_stack) { |
| free((void*)ptr); |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_stack_free_10(uptr ptr, uptr size, uptr real_stack) { |
| free((void*)ptr); |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_version_mismatch_check_v6() { |
| // Do nothing. |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_module_init( |
| int32_t* guards, uptr npcs, uint8_t* counters, const char* comp_unit_name) { |
| } |
| |
| SANITIZER_INTERFACE_ATTRIBUTE |
| void __asan_init() { |
| static int inited = 0; |
| if (inited) return; |
| inited = 1; |
| #if __WORDSIZE == 64 |
| unsigned long start = 0x100000000000; |
| unsigned long size = 0x100000000000; |
| #else |
| unsigned long start = 0x20000000; |
| unsigned long size = 0x20000000; |
| #endif |
| void* res = mmap((void*)start, size, PROT_READ | PROT_WRITE, |
| MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 0, 0); |
| if (res == (void*)start) { |
| fprintf(stderr, "Fake AddressSanitizer run-time initialized ok at %p\n", |
| res); |
| } else { |
| fprintf(stderr, |
| "Fake AddressSanitizer run-time failed to initialize.\n" |
| "You have been warned. Aborting."); |
| abort(); |
| } |
| } |
| } |
| #endif |
| |
| namespace android { |
| namespace vts { |
| |
| static void RemoveDir(char* path) { |
| struct dirent* entry = NULL; |
| DIR* dir = opendir(path); |
| |
| while ((entry = readdir(dir)) != NULL) { |
| DIR* sub_dir = NULL; |
| FILE* file = NULL; |
| char abs_path[4096] = {0}; |
| |
| if (*(entry->d_name) != '.') { |
| sprintf(abs_path, "%s/%s", path, entry->d_name); |
| if ((sub_dir = opendir(abs_path)) != NULL) { |
| closedir(sub_dir); |
| RemoveDir(abs_path); |
| } else if ((file = fopen(abs_path, "r")) != NULL) { |
| fclose(file); |
| remove(abs_path); |
| } |
| } |
| } |
| remove(path); |
| } |
| |
| FuzzerBase::FuzzerBase(int target_class) |
| : device_(NULL), |
| hmi_(NULL), |
| target_dll_path_(NULL), |
| target_class_(target_class), |
| component_filename_(NULL), |
| gcov_output_basepath_(NULL) {} |
| |
| FuzzerBase::~FuzzerBase() { free(component_filename_); } |
| |
| void wfn() { cout << "wfn" << endl; } |
| |
| void ffn() { cout << "ffn" << endl; } |
| |
| bool FuzzerBase::LoadTargetComponent(const char* target_dll_path) { |
| cout << __func__ << ":" << __LINE__ << " entry" << endl; |
| if (target_dll_path && target_dll_path_ && |
| !strcmp(target_dll_path, target_dll_path_)) { |
| cout << __func__ << " skip loading" << endl; |
| return true; |
| } |
| |
| if (!target_loader_.Load(target_dll_path)) return false; |
| target_dll_path_ = (char*)malloc(strlen(target_dll_path) + 1); |
| strcpy(target_dll_path_, target_dll_path); |
| cout << __FUNCTION__ << ":" << __LINE__ << " loaded the target" << endl; |
| if (target_class_ == HAL_LEGACY) return true; |
| cout << __FUNCTION__ << ":" << __LINE__ << " loaded a non-legacy HAL file." |
| << endl; |
| if (target_class_ == HAL_CONVENTIONAL) { |
| hmi_ = target_loader_.InitConventionalHal(); |
| if (!hmi_) { |
| free(target_dll_path_); |
| target_dll_path_ = NULL; |
| return false; |
| } |
| } |
| #if SANCOV |
| cout << __FUNCTION__ << "sancov reset " |
| << target_loader_.SancovResetCoverage() << endl; |
| ; |
| #endif |
| |
| if (target_dll_path_) { |
| string target_path(target_dll_path_); |
| |
| size_t offset = target_path.rfind("/", target_path.length()); |
| if (offset != string::npos) { |
| string filename = |
| target_path.substr(offset + 1, target_path.length() - offset); |
| filename = filename.substr(0, filename.length() - 3 /* for .so */); |
| component_filename_ = (char*)malloc(filename.length() + 1); |
| strcpy(component_filename_, filename.c_str()); |
| cout << __FUNCTION__ << ":" << __LINE__ |
| << " module file name: " << component_filename_ << endl; |
| } |
| cout << __FUNCTION__ << ":" << __LINE__ << " target_dll_path " |
| << target_dll_path_ << endl; |
| } |
| |
| #if USE_GCOV |
| cout << __FUNCTION__ << ": gcov init " << target_loader_.GcovInit(wfn, ffn) |
| << endl; |
| #endif |
| return true; |
| } |
| |
| bool FuzzerBase::GetService() { |
| cerr << __func__ << " not impl" << endl; |
| return false; |
| } |
| |
| int FuzzerBase::OpenConventionalHal(const char* module_name) { |
| cout << __func__ << endl; |
| if (module_name) cout << __func__ << " " << module_name << endl; |
| device_ = target_loader_.OpenConventionalHal(module_name); |
| if (!device_) return -1; |
| cout << __func__ << " device_" << device_ << endl; |
| return 0; |
| } |
| |
| bool FuzzerBase::Fuzz(vts::InterfaceSpecificationMessage* message, |
| void** result) { |
| cout << __func__ << " Fuzzing target component: " |
| << "class " << message->component_class() << " type " |
| << message->component_type() << " version " |
| << message->component_type_version() << endl; |
| |
| string function_name_prefix = GetFunctionNamePrefix(*message); |
| function_name_prefix_ = function_name_prefix.c_str(); |
| for (vts::FunctionSpecificationMessage func_msg : *message->mutable_api()) { |
| Fuzz(&func_msg, result, ""); |
| } |
| return true; |
| } |
| |
| void FuzzerBase::FunctionCallBegin() { |
| char product_path[4096]; |
| char product[128]; |
| char module_basepath[4096]; |
| char cwd[4096]; |
| |
| cout << __func__ << ":" << __LINE__ << " begin" << endl; |
| if (getcwd(cwd, 4096)) { |
| cout << __func__ << ":" << __LINE__ << " cwd = " << cwd << endl; |
| int n = snprintf(product_path, 4096, "%s/out/target/product", cwd); |
| if (n <= 0 || n >= 4096) { |
| cerr << "couln't get product_path" << endl; |
| return; |
| } |
| DIR* srcdir = opendir(product_path); |
| if (!srcdir) { |
| cerr << __func__ << " couln't open " << product_path << endl; |
| return; |
| } |
| |
| int dir_count = 0; |
| struct dirent* dent; |
| while ((dent = readdir(srcdir)) != NULL) { |
| struct stat st; |
| if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) { |
| continue; |
| } |
| if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) { |
| cerr << "error " << dent->d_name << endl; |
| continue; |
| } |
| if (S_ISDIR(st.st_mode)) { |
| cout << __func__ << ":" << __LINE__ << " dir " << dent->d_name << endl; |
| strcpy(product, dent->d_name); |
| dir_count++; |
| } |
| } |
| cout << __func__ << ":" << __LINE__ << endl; |
| closedir(srcdir); |
| cout << __func__ << ":" << __LINE__ << endl; |
| if (dir_count != 1) { |
| cerr << "more than one product dir found." << endl; |
| return; |
| } |
| |
| cout << __func__ << ":" << __LINE__ << endl; |
| n = snprintf(module_basepath, 4096, "%s/%s/obj/SHARED_LIBRARIES", |
| product_path, product); |
| if (n <= 0 || n >= 4096) { |
| cerr << "couln't get module_basepath" << endl; |
| return; |
| } |
| cout << __func__ << ":" << __LINE__ << endl; |
| srcdir = opendir(module_basepath); |
| if (!srcdir) { |
| cerr << __func__ << " couln't open " << module_basepath << endl; |
| return; |
| } |
| |
| cout << __func__ << ":" << __LINE__ << endl; |
| if (component_filename_ != NULL) { |
| dir_count = 0; |
| string target = string(component_filename_) + "_intermediates"; |
| bool hit = false; |
| cout << __func__ << ":" << __LINE__ << endl; |
| while ((dent = readdir(srcdir)) != NULL) { |
| cout << __func__ << ":" << __LINE__ << " " << dent->d_name << endl; |
| struct stat st; |
| if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) { |
| continue; |
| } |
| if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) { |
| cerr << "error " << dent->d_name << endl; |
| continue; |
| } |
| if (S_ISDIR(st.st_mode)) { |
| cout << "module_basepath " << string(dent->d_name) << endl; |
| if (string(dent->d_name) == target) { |
| cout << "hit" << endl; |
| hit = true; |
| } |
| dir_count++; |
| } |
| } |
| cout << __func__ << ":" << __LINE__ << endl; |
| if (hit) { |
| cout << __func__ << ":" << __LINE__ << endl; |
| free(gcov_output_basepath_); |
| gcov_output_basepath_ = |
| (char*)malloc(strlen(module_basepath) + target.length() + 2); |
| if (!gcov_output_basepath_) { |
| cerr << __FUNCTION__ << ": couldn't alloc memory" << endl; |
| return; |
| } |
| sprintf(gcov_output_basepath_, "%s/%s", module_basepath, target.c_str()); |
| RemoveDir(gcov_output_basepath_); |
| } |
| } else { |
| cerr << __func__ << ":" << __LINE__ << " component_filename_ is NULL" |
| << endl; |
| } |
| // TODO: check how it works when there already is a file. |
| closedir(srcdir); |
| } else { |
| cerr << __FUNCTION__ << ": couldn't get the pwd." << endl; |
| } |
| cout << __func__ << ":" << __LINE__ << " end" << endl; |
| } |
| |
| bool FuzzerBase::FunctionCallEnd(FunctionSpecificationMessage* msg) { |
| cout << __FUNCTION__ << ": gcov flush " << endl; |
| cout << __func__ << endl; |
| #if USE_GCOV |
| target_loader_.GcovFlush(); |
| // find the file. |
| if (!gcov_output_basepath_) { |
| cerr << __FUNCTION__ << ": no gcov basepath set" << endl; |
| return false; |
| } |
| DIR* srcdir = opendir(gcov_output_basepath_); |
| if (!srcdir) { |
| cerr << __func__ << " couln't open " << gcov_output_basepath_ << endl; |
| return false; |
| } |
| |
| int dir_count = 0; |
| struct dirent* dent; |
| FILE* gcda_file; |
| while ((dent = readdir(srcdir)) != NULL) { |
| struct stat st; |
| if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) { |
| continue; |
| } |
| if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) { |
| cerr << "error " << dent->d_name << endl; |
| continue; |
| } |
| if (!S_ISDIR(st.st_mode)) { |
| cout << dent->d_name << endl; |
| if (string(dent->d_name).rfind(".gcda") != string::npos) { |
| char* buffer; |
| buffer = (char*)malloc(strlen(gcov_output_basepath_) + |
| strlen(dent->d_name) + 2); |
| if (!buffer) { |
| cerr << __FUNCTION__ << ": OOM" << endl; |
| closedir(srcdir); |
| return false; |
| } |
| sprintf(buffer, "%s/%s", gcov_output_basepath_, dent->d_name); |
| |
| vector<unsigned>* processed_data = android::vts::parse_gcda_file(buffer); |
| for (const auto& data : *processed_data) { |
| msg->mutable_processed_coverage_data()->Add(data); |
| } |
| |
| gcda_file = fopen(buffer, "rb"); |
| if (!gcda_file) { |
| cerr << "Unable to open a gcda file. " << buffer << endl; |
| } else { |
| cout << "Opened a gcda file. " << buffer << endl; |
| fseek(gcda_file, 0, SEEK_END); |
| long gcda_file_size = ftell(gcda_file); |
| cout << "File size " << gcda_file_size << " bytes" << endl; |
| fseek(gcda_file, 0, SEEK_SET); |
| |
| char* gcda_file_buffer = (char*)malloc(gcda_file_size + 1); |
| if (!gcda_file_buffer) { |
| cerr << "Unable to allocate memory to read a gcda file. " << endl; |
| } else { |
| if (fread(gcda_file_buffer, gcda_file_size, 1, gcda_file) != 1) { |
| cerr << "File read error" << endl; |
| } else { |
| gcda_file_buffer[gcda_file_size] = '\0'; |
| NativeCodeCoverageRawDataMessage* raw_msg = |
| msg->mutable_raw_coverage_data()->Add(); |
| raw_msg->set_file_path(dent->d_name); |
| string gcda_file_buffer_string(gcda_file_buffer, gcda_file_size); |
| raw_msg->set_gcda(gcda_file_buffer_string); |
| free(gcda_file_buffer); |
| } |
| } |
| fclose(gcda_file); |
| } |
| #if USE_GCOV_DEBUG |
| if (result) { |
| for (unsigned int index = 0; index < result->size(); index++) { |
| cout << result->at(index) << endl; |
| } |
| } |
| #endif |
| free(buffer); |
| break; |
| } |
| } |
| } |
| closedir(srcdir); |
| #endif |
| return true; |
| } |
| |
| } // namespace vts |
| } // namespace android |