1 /* 2 * Copyright (C) 2020 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 <fstream> 18 #include <memory> 19 #include <stddef.h> 20 #include <stdint.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <string> 24 #include <sys/types.h> 25 #include <unistd.h> 26 #include "audio_utils/sndfile.h" 27 #include <android-base/scopeguard.h> 28 29 #define MAX_BUFFER_SIZE 0x00005000 30 #define MAX_FRAME_READ_COUNT 100 31 #define MAX_FRAME_COUNT 1000 32 33 #ifdef SNDFILE_FUZZER_HOST 34 // the path is located in shared memory, so it can accelerate fuzzing on host 35 // however, the path is not supported on device 36 #define TEMP_DATA_PATH "/dev/shm/sndfile_fuzzer.tmp" 37 #else 38 #define TEMP_DATA_PATH "/data/local/tmp/sndfile_fuzzer.tmp" 39 #endif 40 41 // create a unique path so that the fuzzer can be run parallelly 42 std::string getUniquePath() { 43 pid_t pid = getpid(); 44 std::string unique_path = TEMP_DATA_PATH + std::to_string(pid); 45 return unique_path; 46 } 47 48 int parseValue(const uint8_t *src, int index, void *dst, size_t size) { 49 memcpy(dst, &src[index], size); 50 return size; 51 } 52 53 size_t getSizeByType(uint32_t input_format) { 54 switch (input_format) { 55 case 0: return sizeof(short); 56 case 1: return sizeof(int); 57 case 2: return sizeof(float); 58 default: return sizeof(short); 59 } 60 } 61 62 sf_count_t sfReadfWithType(uint32_t input_format, SNDFILE *handle, 63 const void *ptr, sf_count_t desired) { 64 switch (input_format) { 65 case 0: return sf_readf_short(handle, (short *)ptr, desired); 66 case 1: return sf_readf_int(handle, (int *)ptr, desired); 67 case 2: return sf_readf_float(handle, (float *)ptr, desired); 68 default: return 0; 69 } 70 } 71 72 // the corpus of this fuzzer is generated by : 73 // printf "\x01\x00\x00\x00\x01\x00\x00\x00" | \ 74 // cat - 2020_06_10_15_56_20.wav > merged_corpus 75 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *bytes, size_t size) { 76 uint32_t desired_frame_count = 1; 77 uint32_t input_format = 0; 78 79 size_t metadata_size = sizeof(desired_frame_count) + sizeof(input_format); 80 if (size < metadata_size) { 81 return 0; 82 } 83 84 int idx = 0; 85 idx += 86 parseValue(bytes, idx, &desired_frame_count, sizeof(desired_frame_count)); 87 idx += parseValue(bytes, idx, &input_format, sizeof(input_format)); 88 89 desired_frame_count %= MAX_FRAME_READ_COUNT; 90 input_format %= 3; 91 92 // write bytes to a file 93 std::string path = getUniquePath(); 94 std::ofstream file; 95 file.open(path.c_str(), std::ios::trunc | std::ios::binary | std::ios::out); 96 if (!file.is_open()) { 97 return 0; 98 } 99 100 file.write((char *)(bytes + idx), size - idx); 101 file.close(); 102 // ensure file is unlinked after use 103 auto scope_guard = 104 android::base::make_scope_guard([path] { remove(path.c_str()); }); 105 106 SF_INFO info; 107 // when format is set to zero, all other field are filled in by the lib 108 info.format = 0; 109 std::unique_ptr<SNDFILE, decltype(&sf_close)> handle( 110 sf_open(path.c_str(), SFM_READ, &info), &sf_close); 111 112 if (handle == nullptr) { 113 return 0; 114 } 115 116 // sndfile support three different data types to read regardless the original 117 // data type in file. the library handles the data conversion. The size of 118 // input is parsed from file; malloc buffer by the size is risky, but it 119 // cannot be fuzzed at this level. Here, we only ensure the read APIs does not 120 // write memory outside the buffer. 121 size_t input_size = 122 getSizeByType(input_format) * desired_frame_count * info.channels; 123 124 if (input_size > MAX_BUFFER_SIZE) { 125 return 0; 126 } 127 128 void *dst_buffer = malloc(input_size); 129 if (dst_buffer == nullptr) { 130 return 0; 131 } 132 133 sf_count_t read_frame_count = 0; 134 sf_count_t frame_count = 0; 135 do { 136 read_frame_count = sfReadfWithType(input_format, handle.get(), dst_buffer, 137 desired_frame_count); 138 frame_count += read_frame_count; 139 } while (read_frame_count > 0 && frame_count < MAX_FRAME_COUNT); 140 free(dst_buffer); 141 142 return 0; 143 }