Loading media/libstagefright/codecs/mp3dec/Android.bp +7 −0 Original line number Original line Diff line number Diff line Loading @@ -2,6 +2,7 @@ cc_library_static { name: "libstagefright_mp3dec", name: "libstagefright_mp3dec", vendor_available: true, vendor_available: true, host_supported:true, srcs: [ srcs: [ "src/pvmp3_normalize.cpp", "src/pvmp3_normalize.cpp", "src/pvmp3_alias_reduction.cpp", "src/pvmp3_alias_reduction.cpp", Loading Loading @@ -72,6 +73,12 @@ cc_library_static { "-DOSCL_UNUSED_ARG(x)=(void)(x)", "-DOSCL_UNUSED_ARG(x)=(void)(x)", "-Werror", "-Werror", ], ], target: { darwin: { enabled: false, }, }, } } //############################################################################### //############################################################################### Loading media/libstagefright/codecs/mp3dec/fuzzer/Android.bp 0 → 100644 +32 −0 Original line number Original line Diff line number Diff line /****************************************************************************** * * Copyright (C) 2020 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. * ***************************************************************************** * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore */ cc_fuzz { name: "mp3_dec_fuzzer", host_supported: true, static_libs: [ "libstagefright_mp3dec", ], srcs: [ "mp3_dec_fuzzer.cpp", ], } media/libstagefright/codecs/mp3dec/fuzzer/README.md 0 → 100644 +56 −0 Original line number Original line Diff line number Diff line # Fuzzer for libstagefright_mp3dec decoder ## Plugin Design Considerations The fuzzer plugin for mp3 decoder is designed based on the understanding of the codec and tries to achieve the following: ##### Maximize code coverage This fuzzer makes use of the following config parameters: 1. Equalizer type (parameter name: `equalizerType`) | Parameter| Valid Values| Configured Value| |------------- |-------------| ----- | | `equalizerType` | 0. `flat ` 1. `bass_boost ` 2. `rock ` 3. `pop ` 4. `jazz ` 5. `classical ` 6. `talk ` 7. `flat_ ` | Bits 0, 1 and 2 of first byte of input stream | | `crcEnabled` | 0. `false ` 1. `true `| Bit 0 of second byte of input stream | ##### Maximize utilization of input data The plugin feeds the entire input data to the codec using a loop. * If the decode operation was successful, the input is advanced by the number of bytes used by the decoder. * If the decode operation was un-successful, the input is advanced by 1 byte till it reaches a valid frame or end of stream. This ensures that the plugin tolerates any kind of input (empty, huge, malformed, etc) and doesnt `exit()` on any input and thereby increasing the chance of identifying vulnerabilities. ## Build This describes steps to build mp3_dec_fuzzer binary. ### Android #### Steps to build Build the fuzzer ``` $ mm -j$(nproc) mp3_dec_fuzzer ``` #### Steps to run Create a directory CORPUS_DIR and copy some mp3 files to that folder. Push this directory to device. To run on device ``` $ adb sync data $ adb shell /data/fuzz/arm64/mp3_dec_fuzzer/mp3_dec_fuzzer CORPUS_DIR ``` To run on host ``` $ $ANDROID_HOST_OUT/fuzz/x86_64/mp3_dec_fuzzer/mp3_dec_fuzzer CORPUS_DIR ``` ## References: * http://llvm.org/docs/LibFuzzer.html * https://github.com/google/oss-fuzz media/libstagefright/codecs/mp3dec/fuzzer/mp3_dec_fuzzer.cpp 0 → 100644 +237 −0 Original line number Original line Diff line number Diff line /****************************************************************************** * * Copyright (C) 2020 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. * ***************************************************************************** * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore */ #include <stdlib.h> #include <algorithm> #include <pvmp3decoder_api.h> constexpr int kMaxFrameSamples = 4608; constexpr int kMaxChannels = 2; constexpr e_equalization kEqualizerTypes[] = {flat, bass_boost, rock, pop, jazz, classical, talk, flat_}; static bool parseMp3Header(uint32_t header, size_t *frame_size, uint32_t *out_sampling_rate = nullptr, uint32_t *out_channels = nullptr, uint32_t *out_bitrate = nullptr, uint32_t *out_num_samples = nullptr) { *frame_size = 0; if (out_sampling_rate) *out_sampling_rate = 0; if (out_channels) *out_channels = 0; if (out_bitrate) *out_bitrate = 0; if (out_num_samples) *out_num_samples = 0; if ((header & 0xffe00000) != 0xffe00000) { return false; } unsigned version = (header >> 19) & 3; if (version == 0x01) { return false; } unsigned layer = (header >> 17) & 3; if (layer == 0x00) { return false; } unsigned bitrate_index = (header >> 12) & 0x0f; if (bitrate_index == 0 || bitrate_index == 0x0f) { return false; } unsigned sampling_rate_index = (header >> 10) & 3; if (sampling_rate_index == 3) { return false; } static const int kSamplingRateV1[] = {44100, 48000, 32000}; int sampling_rate = kSamplingRateV1[sampling_rate_index]; if (version == 2 /* V2 */) { sampling_rate /= 2; } else if (version == 0 /* V2.5 */) { sampling_rate /= 4; } unsigned padding = (header >> 9) & 1; if (layer == 3) { // layer I static const int kBitrateV1[] = {32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448}; static const int kBitrateV2[] = {32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256}; int bitrate = (version == 3 /* V1 */) ? kBitrateV1[bitrate_index - 1] : kBitrateV2[bitrate_index - 1]; if (out_bitrate) { *out_bitrate = bitrate; } *frame_size = (12000 * bitrate / sampling_rate + padding) * 4; if (out_num_samples) { *out_num_samples = 384; } } else { // layer II or III static const int kBitrateV1L2[] = {32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384}; static const int kBitrateV1L3[] = {32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320}; static const int kBitrateV2[] = {8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}; int bitrate; if (version == 3 /* V1 */) { bitrate = (layer == 2 /* L2 */) ? kBitrateV1L2[bitrate_index - 1] : kBitrateV1L3[bitrate_index - 1]; if (out_num_samples) { *out_num_samples = 1152; } } else { // V2 (or 2.5) bitrate = kBitrateV2[bitrate_index - 1]; if (out_num_samples) { *out_num_samples = (layer == 1 /* L3 */) ? 576 : 1152; } } if (out_bitrate) { *out_bitrate = bitrate; } if (version == 3 /* V1 */) { *frame_size = 144000 * bitrate / sampling_rate + padding; } else { // V2 or V2.5 size_t tmp = (layer == 1 /* L3 */) ? 72000 : 144000; *frame_size = tmp * bitrate / sampling_rate + padding; } } if (out_sampling_rate) { *out_sampling_rate = sampling_rate; } if (out_channels) { int channel_mode = (header >> 6) & 3; *out_channels = (channel_mode == 3) ? 1 : 2; } return true; } static uint32_t U32_AT(const uint8_t *ptr) { return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3]; } static bool checkHeader(uint8 *header, size_t inSize) { size_t frameSize; size_t totalInSize = 0; bool isValidBuffer = false; while (totalInSize + 4 < inSize) { isValidBuffer = true; uint32_t val = U32_AT(header + totalInSize); if (!parseMp3Header(val, &frameSize, nullptr, nullptr, nullptr, nullptr)) { return false; } totalInSize += frameSize; } return (isValidBuffer); } class Codec { public: Codec() = default; ~Codec() { deInitDecoder(); } bool initDecoder(); void decodeFrames(uint8_t *data, size_t size); void deInitDecoder(); private: tPVMP3DecoderExternal *mConfig = nullptr; void *mDecoderBuf = nullptr; }; bool Codec::initDecoder() { mConfig = new tPVMP3DecoderExternal{}; if (!mConfig) { return false; } size_t decoderBufSize = pvmp3_decoderMemRequirements(); mDecoderBuf = malloc(decoderBufSize); if (!mDecoderBuf) { return false; } memset(mDecoderBuf, 0x0, decoderBufSize); pvmp3_InitDecoder(mConfig, mDecoderBuf); return true; } void Codec::decodeFrames(uint8_t *data, size_t size) { uint8_t equalizerTypeValue = (data[0] & 0x7); mConfig->equalizerType = kEqualizerTypes[equalizerTypeValue]; mConfig->crcEnabled = data[1] & 0x1; while (size > 0) { bool status = checkHeader(data, size); if (!status) { size--; data++; continue; } size_t outBufSize = kMaxFrameSamples * kMaxChannels; size_t usedBytes = 0; int16_t outputBuf[outBufSize]; mConfig->inputBufferCurrentLength = size; mConfig->inputBufferUsedLength = 0; mConfig->inputBufferMaxLength = 0; mConfig->pInputBuffer = data; mConfig->pOutputBuffer = outputBuf; mConfig->outputFrameSize = outBufSize / sizeof(int16_t); ERROR_CODE decoderErr; decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf); if (decoderErr != NO_DECODING_ERROR) { size--; data++; } else { usedBytes = std::min((int32_t)size, mConfig->inputBufferUsedLength); size -= usedBytes; data += usedBytes; } } } void Codec::deInitDecoder() { if (mDecoderBuf) { free(mDecoderBuf); mDecoderBuf = nullptr; } delete mConfig; mConfig = nullptr; } extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { if (size < 4) { return 0; } Codec *codec = new Codec(); if (!codec) { return 0; } if (codec->initDecoder()) { codec->decodeFrames(const_cast<uint8_t *>(data), size); } delete codec; return 0; } Loading
media/libstagefright/codecs/mp3dec/Android.bp +7 −0 Original line number Original line Diff line number Diff line Loading @@ -2,6 +2,7 @@ cc_library_static { name: "libstagefright_mp3dec", name: "libstagefright_mp3dec", vendor_available: true, vendor_available: true, host_supported:true, srcs: [ srcs: [ "src/pvmp3_normalize.cpp", "src/pvmp3_normalize.cpp", "src/pvmp3_alias_reduction.cpp", "src/pvmp3_alias_reduction.cpp", Loading Loading @@ -72,6 +73,12 @@ cc_library_static { "-DOSCL_UNUSED_ARG(x)=(void)(x)", "-DOSCL_UNUSED_ARG(x)=(void)(x)", "-Werror", "-Werror", ], ], target: { darwin: { enabled: false, }, }, } } //############################################################################### //############################################################################### Loading
media/libstagefright/codecs/mp3dec/fuzzer/Android.bp 0 → 100644 +32 −0 Original line number Original line Diff line number Diff line /****************************************************************************** * * Copyright (C) 2020 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. * ***************************************************************************** * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore */ cc_fuzz { name: "mp3_dec_fuzzer", host_supported: true, static_libs: [ "libstagefright_mp3dec", ], srcs: [ "mp3_dec_fuzzer.cpp", ], }
media/libstagefright/codecs/mp3dec/fuzzer/README.md 0 → 100644 +56 −0 Original line number Original line Diff line number Diff line # Fuzzer for libstagefright_mp3dec decoder ## Plugin Design Considerations The fuzzer plugin for mp3 decoder is designed based on the understanding of the codec and tries to achieve the following: ##### Maximize code coverage This fuzzer makes use of the following config parameters: 1. Equalizer type (parameter name: `equalizerType`) | Parameter| Valid Values| Configured Value| |------------- |-------------| ----- | | `equalizerType` | 0. `flat ` 1. `bass_boost ` 2. `rock ` 3. `pop ` 4. `jazz ` 5. `classical ` 6. `talk ` 7. `flat_ ` | Bits 0, 1 and 2 of first byte of input stream | | `crcEnabled` | 0. `false ` 1. `true `| Bit 0 of second byte of input stream | ##### Maximize utilization of input data The plugin feeds the entire input data to the codec using a loop. * If the decode operation was successful, the input is advanced by the number of bytes used by the decoder. * If the decode operation was un-successful, the input is advanced by 1 byte till it reaches a valid frame or end of stream. This ensures that the plugin tolerates any kind of input (empty, huge, malformed, etc) and doesnt `exit()` on any input and thereby increasing the chance of identifying vulnerabilities. ## Build This describes steps to build mp3_dec_fuzzer binary. ### Android #### Steps to build Build the fuzzer ``` $ mm -j$(nproc) mp3_dec_fuzzer ``` #### Steps to run Create a directory CORPUS_DIR and copy some mp3 files to that folder. Push this directory to device. To run on device ``` $ adb sync data $ adb shell /data/fuzz/arm64/mp3_dec_fuzzer/mp3_dec_fuzzer CORPUS_DIR ``` To run on host ``` $ $ANDROID_HOST_OUT/fuzz/x86_64/mp3_dec_fuzzer/mp3_dec_fuzzer CORPUS_DIR ``` ## References: * http://llvm.org/docs/LibFuzzer.html * https://github.com/google/oss-fuzz
media/libstagefright/codecs/mp3dec/fuzzer/mp3_dec_fuzzer.cpp 0 → 100644 +237 −0 Original line number Original line Diff line number Diff line /****************************************************************************** * * Copyright (C) 2020 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. * ***************************************************************************** * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore */ #include <stdlib.h> #include <algorithm> #include <pvmp3decoder_api.h> constexpr int kMaxFrameSamples = 4608; constexpr int kMaxChannels = 2; constexpr e_equalization kEqualizerTypes[] = {flat, bass_boost, rock, pop, jazz, classical, talk, flat_}; static bool parseMp3Header(uint32_t header, size_t *frame_size, uint32_t *out_sampling_rate = nullptr, uint32_t *out_channels = nullptr, uint32_t *out_bitrate = nullptr, uint32_t *out_num_samples = nullptr) { *frame_size = 0; if (out_sampling_rate) *out_sampling_rate = 0; if (out_channels) *out_channels = 0; if (out_bitrate) *out_bitrate = 0; if (out_num_samples) *out_num_samples = 0; if ((header & 0xffe00000) != 0xffe00000) { return false; } unsigned version = (header >> 19) & 3; if (version == 0x01) { return false; } unsigned layer = (header >> 17) & 3; if (layer == 0x00) { return false; } unsigned bitrate_index = (header >> 12) & 0x0f; if (bitrate_index == 0 || bitrate_index == 0x0f) { return false; } unsigned sampling_rate_index = (header >> 10) & 3; if (sampling_rate_index == 3) { return false; } static const int kSamplingRateV1[] = {44100, 48000, 32000}; int sampling_rate = kSamplingRateV1[sampling_rate_index]; if (version == 2 /* V2 */) { sampling_rate /= 2; } else if (version == 0 /* V2.5 */) { sampling_rate /= 4; } unsigned padding = (header >> 9) & 1; if (layer == 3) { // layer I static const int kBitrateV1[] = {32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448}; static const int kBitrateV2[] = {32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256}; int bitrate = (version == 3 /* V1 */) ? kBitrateV1[bitrate_index - 1] : kBitrateV2[bitrate_index - 1]; if (out_bitrate) { *out_bitrate = bitrate; } *frame_size = (12000 * bitrate / sampling_rate + padding) * 4; if (out_num_samples) { *out_num_samples = 384; } } else { // layer II or III static const int kBitrateV1L2[] = {32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384}; static const int kBitrateV1L3[] = {32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320}; static const int kBitrateV2[] = {8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}; int bitrate; if (version == 3 /* V1 */) { bitrate = (layer == 2 /* L2 */) ? kBitrateV1L2[bitrate_index - 1] : kBitrateV1L3[bitrate_index - 1]; if (out_num_samples) { *out_num_samples = 1152; } } else { // V2 (or 2.5) bitrate = kBitrateV2[bitrate_index - 1]; if (out_num_samples) { *out_num_samples = (layer == 1 /* L3 */) ? 576 : 1152; } } if (out_bitrate) { *out_bitrate = bitrate; } if (version == 3 /* V1 */) { *frame_size = 144000 * bitrate / sampling_rate + padding; } else { // V2 or V2.5 size_t tmp = (layer == 1 /* L3 */) ? 72000 : 144000; *frame_size = tmp * bitrate / sampling_rate + padding; } } if (out_sampling_rate) { *out_sampling_rate = sampling_rate; } if (out_channels) { int channel_mode = (header >> 6) & 3; *out_channels = (channel_mode == 3) ? 1 : 2; } return true; } static uint32_t U32_AT(const uint8_t *ptr) { return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3]; } static bool checkHeader(uint8 *header, size_t inSize) { size_t frameSize; size_t totalInSize = 0; bool isValidBuffer = false; while (totalInSize + 4 < inSize) { isValidBuffer = true; uint32_t val = U32_AT(header + totalInSize); if (!parseMp3Header(val, &frameSize, nullptr, nullptr, nullptr, nullptr)) { return false; } totalInSize += frameSize; } return (isValidBuffer); } class Codec { public: Codec() = default; ~Codec() { deInitDecoder(); } bool initDecoder(); void decodeFrames(uint8_t *data, size_t size); void deInitDecoder(); private: tPVMP3DecoderExternal *mConfig = nullptr; void *mDecoderBuf = nullptr; }; bool Codec::initDecoder() { mConfig = new tPVMP3DecoderExternal{}; if (!mConfig) { return false; } size_t decoderBufSize = pvmp3_decoderMemRequirements(); mDecoderBuf = malloc(decoderBufSize); if (!mDecoderBuf) { return false; } memset(mDecoderBuf, 0x0, decoderBufSize); pvmp3_InitDecoder(mConfig, mDecoderBuf); return true; } void Codec::decodeFrames(uint8_t *data, size_t size) { uint8_t equalizerTypeValue = (data[0] & 0x7); mConfig->equalizerType = kEqualizerTypes[equalizerTypeValue]; mConfig->crcEnabled = data[1] & 0x1; while (size > 0) { bool status = checkHeader(data, size); if (!status) { size--; data++; continue; } size_t outBufSize = kMaxFrameSamples * kMaxChannels; size_t usedBytes = 0; int16_t outputBuf[outBufSize]; mConfig->inputBufferCurrentLength = size; mConfig->inputBufferUsedLength = 0; mConfig->inputBufferMaxLength = 0; mConfig->pInputBuffer = data; mConfig->pOutputBuffer = outputBuf; mConfig->outputFrameSize = outBufSize / sizeof(int16_t); ERROR_CODE decoderErr; decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf); if (decoderErr != NO_DECODING_ERROR) { size--; data++; } else { usedBytes = std::min((int32_t)size, mConfig->inputBufferUsedLength); size -= usedBytes; data += usedBytes; } } } void Codec::deInitDecoder() { if (mDecoderBuf) { free(mDecoderBuf); mDecoderBuf = nullptr; } delete mConfig; mConfig = nullptr; } extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { if (size < 4) { return 0; } Codec *codec = new Codec(); if (!codec) { return 0; } if (codec->initDecoder()) { codec->decodeFrames(const_cast<uint8_t *>(data), size); } delete codec; return 0; }