diff options
-rw-r--r-- | Android.bp | 38 | ||||
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | METADATA | 1 | ||||
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | add-test/add_test.c | 4 | ||||
-rw-r--r-- | fuzzer/Android.bp | 58 | ||||
-rw-r--r-- | fuzzer/README.md | 78 | ||||
-rw-r--r-- | fuzzer/gsm_dec_fuzzer.cpp | 98 | ||||
-rw-r--r-- | fuzzer/gsm_enc_fuzzer.cpp | 96 | ||||
-rw-r--r-- | inc/config.h | 2 | ||||
-rw-r--r-- | inc/gsm.h | 10 | ||||
-rw-r--r-- | inc/private.h | 8 | ||||
-rw-r--r-- | inc/toast.h | 4 |
13 files changed, 408 insertions, 6 deletions
@@ -14,9 +14,41 @@ // limitations under the License. // +package { + default_applicable_licenses: ["external_libgsm_license"], +} + +// Added automatically by a large-scale-change that took the approach of +// 'apply every license found to every target'. While this makes sure we respect +// every license restriction, it may not be entirely correct. +// +// e.g. GPL in an MIT project might only apply to the contrib/ directory. +// +// Please consider splitting the single license below into multiple licenses, +// taking care not to lose any license_kind information, and overriding the +// default license using the 'licenses: [...]' property on targets as needed. +// +// For unused files, consider creating a 'fileGroup' with "//visibility:private" +// to attach the license to, and including a comment whether the files may be +// used in the current project. +// See: http://go/android-license-faq +license { + name: "external_libgsm_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-0BSD", + "SPDX-license-identifier-Apache-2.0", + "SPDX-license-identifier-BSD", + ], + license_text: [ + "COPYRIGHT", + ], +} + cc_library_static { name: "libgsm", vendor_available: true, + host_supported: true, srcs: [ "src/add.c", @@ -43,6 +75,12 @@ cc_library_static { "-Wno-unused-parameter", ], + target: { + darwin: { + enabled: false, + }, + }, + export_include_dirs: ["inc"], min_sdk_version: "apex_inherit", } @@ -1,3 +1,12 @@ +Fri Mar 27 15:18:06 2020 + + * Release 1.0 Patchlevel 19 + Make it easier to include gsm.h from C++ by wrapping it with macros. + Throw a #define _POSIX_C_SOURCE 200809L into toast.h to make it + possible for Linux glibc to just work. + (Thanks to enh@google.com for the suggestion; errors are mine.) + Switch from compress/.Z to gzip/.gz + Sat May 5 21:48:20 2018 * Release 1.0 Patchlevel 18 @@ -10,6 +10,7 @@ third_party { value: "http://www.quut.com/gsm/gsm-1.0.18.tar.gz" } version: "1.0.18" + license_type: NOTICE last_upgrade_date { year: 2018 month: 12 @@ -102,7 +102,7 @@ AR = ar ARFLAGS = cr RMFLAGS = FIND = find -COMPRESS = compress +COMPRESS = gzip COMPRESSFLAGS = # RANLIB = true RANLIB = ranlib @@ -401,14 +401,14 @@ $(GSM_INSTALL_LIB)/libgsm.a: $(LIBGSM) # Distribution -dist: gsm-1.0.tar.Z +dist: gsm-1.0.tar.gz @echo dist: Done. -gsm-1.0.tar.Z: $(STUFF) $(SOURCES) $(HEADERS) $(MANUALS) +gsm-1.0.tar.gz: $(STUFF) $(SOURCES) $(HEADERS) $(MANUALS) ( cd $(ROOT)/..; \ tar cvf - `cat $(ROOT)/gsm-1.0/MANIFEST \ | sed '/^#/d'` \ - ) | $(COMPRESS) $(COMPRESSFLAGS) > $(ROOT)/gsm-1.0.tar.Z + ) | $(COMPRESS) $(COMPRESSFLAGS) > $(ROOT)/gsm-1.0.tar.gz # Clean diff --git a/add-test/add_test.c b/add-test/add_test.c index 6b23e9d..bf0e4b1 100644 --- a/add-test/add_test.c +++ b/add-test/add_test.c @@ -6,6 +6,10 @@ /* $Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/add_test.c,v 1.2 1994/05/10 20:18:17 jutta Exp $ */ +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif + #include <stdio.h> #include <stdlib.h> #include <string.h> diff --git a/fuzzer/Android.bp b/fuzzer/Android.bp new file mode 100644 index 0000000..3dc0524 --- /dev/null +++ b/fuzzer/Android.bp @@ -0,0 +1,58 @@ +/****************************************************************************** + * + * 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 + */ + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "external_libgsm_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["external_libgsm_license"], +} + +cc_defaults { + name: "gsm_fuzzer_defaults", + host_supported: true, + static_libs: [ + "libgsm", + ], + fuzz_config: { + cc: [ + "android-media-fuzzing-reports@google.com", + ], + componentid: 155276, + }, +} + +cc_fuzz { + name: "gsm_dec_fuzzer", + defaults: ["gsm_fuzzer_defaults"], + srcs: [ + "gsm_dec_fuzzer.cpp", + ], +} + +cc_fuzz { + name: "gsm_enc_fuzzer", + defaults: ["gsm_fuzzer_defaults"], + srcs: [ + "gsm_enc_fuzzer.cpp", + ], +} diff --git a/fuzzer/README.md b/fuzzer/README.md new file mode 100644 index 0000000..2c3f35f --- /dev/null +++ b/fuzzer/README.md @@ -0,0 +1,78 @@ +# Fuzzer for libgsm codec + +## Plugin Design Considerations +The fuzzer plugin for GSM is designed based on the understanding of the +codec and tries to achieve the following: + +##### Maximize code coverage +The configuration parameters are not hardcoded, but instead selected based on +incoming data. This ensures more code paths are reached by the fuzzer. + +GSM supports the following options: +1. Verbosity (parameter name: `GSM_VERBOSE`) +2. Fastness (parameter name: `GSM_OPT_FAST`) +3. WAV49 Format (parameter name: `GSM_OPT_WAV49`) +4. LTP Cut speed-up (encoder only) (parameter name: `GSM_OPT_LTP_CUT`) + +| Parameter| Valid Values| Configured Value| +|------------- |-------------| ----- | +| `GSM_VERBOSE` | 0. `Verbosity disabled` 1. `Verbosity enabled` | Bit 0 (LSB) of 1st byte of data. | +| `GSM_OPT_FAST` | 0. `Regular algorithm will be used` 1. `Faster version of the algorithm will be used` | Bit 1 (LSB) of 1st byte of data. | +| `GSM_OPT_LTP_CUT` | 0. `Disable LTP cut-off optimization` 1. `Enable LTP cut-off optimization` | Bit 2 (LSB) of 1st byte of data. | +| `GSM_OPT_WAV49` | 0. `Disable WAV49 output in the encoder.` 1. `Enable WAV49 format in the encoder.` | Bit 3 (LSB) of 1st byte of data. | + +This also ensures that the plugin is always deterministic for any given input. + +##### Maximize utilization of input data +The plugin feeds the entire input data to the codec using a loop. +###### For the Decoder: + * If the size of media file is less than 65 bytes, (65 - size) bytes are padded and then sent to + the decoder so that decode happens for all the input files, regardless of their size. + GSM decoder consumes alternating frames of 33 and 32 bytes, so 65 bytes of input are needed. + * If the decode operation was successful, the input is advanced by the frame size + * If the decode operation was un-successful, the input is still advanced by frame size so +that the fuzzer can proceed to feed the next frame. +###### For the Encoder: + * If the size of media file is less than 320 bytes(160 signed 16-bit words), bytes are padded and then sent to + the encoder so that encode happens for all the input files, regardless of their size. + GSM encoder consumes 160 signed 16-bit words, so 320 bytes of input are needed. + * If the encode operation was successful, the input is advanced by the frame size + * If the encode operation was un-successful, the input is still advanced by frame size so +that the fuzzer can proceed to feed the next frame. + +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 gsm_dec_fuzzer and gsm_enc_fuzzer binaries. + +### Android + +#### Steps to build +Build the fuzzer +``` + $ mm -j$(nproc) gsm_dec_fuzzer + $ mm -j$(nproc) gsm_enc_fuzzer +``` + +#### Steps to run +Create a directory CORPUS_DIR and copy some gsm files (decoder)/raw files (encoder) to that folder +Push this directory to device. + +To run on device +``` + $ adb sync data + $ adb shell /data/fuzz/arm64/gsm_dec_fuzzer/gsm_dec_fuzzer CORPUS_DIR + $ adb shell /data/fuzz/arm64/gsm_enc_fuzzer/gsm_enc_fuzzer CORPUS_DIR +``` +To run on host +``` + $ $ANDROID_HOST_OUT/fuzz/x86_64/gsm_dec_fuzzer/gsm_dec_fuzzer CORPUS_DIR + $ $ANDROID_HOST_OUT/fuzz/x86_64/gsm_enc_fuzzer/gsm_enc_fuzzer CORPUS_DIR +``` + +## References: + * http://llvm.org/docs/LibFuzzer.html + * https://github.com/google/oss-fuzz diff --git a/fuzzer/gsm_dec_fuzzer.cpp b/fuzzer/gsm_dec_fuzzer.cpp new file mode 100644 index 0000000..f981eb7 --- /dev/null +++ b/fuzzer/gsm_dec_fuzzer.cpp @@ -0,0 +1,98 @@ +/****************************************************************************** + * + * 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 <stdint.h> +#include <string.h> +#include "gsm.h" + +constexpr int16_t kGsmInFrameSize = 33; +constexpr int16_t kGsmInFrameSizeMinus1 = kGsmInFrameSize - 1; +constexpr int16_t kGsmOutFrameSize = 160; +constexpr int16_t kGsmTotalInFrameSize = (kGsmInFrameSize + kGsmInFrameSizeMinus1); +constexpr int16_t kGsmTotalOutFrameSize = (kGsmOutFrameSize * 2); + +class Codec { + public: + Codec() = default; + ~Codec() { deInitDecoder(); } + bool initDecoder(); + void decodeFrames(const uint8_t *data, size_t size); + void deInitDecoder(); + + private: + gsm mGsm = nullptr; +}; + +bool Codec::initDecoder() { + mGsm = gsm_create(); + if (mGsm) { + int msopt = 1; + gsm_option(mGsm, GSM_OPT_WAV49, &msopt); + return true; + } else { + return false; + } +} + +void Codec::decodeFrames(const uint8_t *data, size_t size) { + uint8_t firstByte = *data; + int32_t verbosity = firstByte & 0x01; + int32_t fast = (firstByte >> 1) & 0x01; + gsm_option(mGsm, GSM_OPT_VERBOSE, &verbosity); + gsm_option(mGsm, GSM_OPT_FAST, &fast); + gsm_byte *readPointer = const_cast<uint8_t *>(data); + uint8_t tmpData[kGsmTotalInFrameSize]; + gsm_signal out[kGsmTotalOutFrameSize]; + + while (size > 0) { + if (size < kGsmTotalInFrameSize) { + memset(tmpData, 0, sizeof(tmpData)); + memcpy(tmpData, data, size); + size = kGsmTotalInFrameSize; + readPointer = tmpData; + } + gsm_decode(mGsm, readPointer, out); + readPointer += kGsmInFrameSize; + size -= kGsmInFrameSize; + + gsm_decode(mGsm, readPointer, out); + readPointer += kGsmInFrameSizeMinus1; + size -= kGsmInFrameSizeMinus1; + } +} + +void Codec::deInitDecoder() { + gsm_destroy(mGsm); + mGsm = nullptr; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + if (size < 1) { + return 0; + } + Codec *codec = new Codec(); + if (!codec) { + return 0; + } + if (codec->initDecoder()) { + codec->decodeFrames(data, size); + } + delete codec; + return 0; +} diff --git a/fuzzer/gsm_enc_fuzzer.cpp b/fuzzer/gsm_enc_fuzzer.cpp new file mode 100644 index 0000000..3e00f85 --- /dev/null +++ b/fuzzer/gsm_enc_fuzzer.cpp @@ -0,0 +1,96 @@ +/****************************************************************************** + * + * 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 <stdint.h> +#include <string.h> +#include <algorithm> + +#include "gsm.h" + +constexpr size_t kGsmInNumSamples = 160; +constexpr size_t kGsmInBufferSize = kGsmInNumSamples * sizeof(gsm_signal); + +enum { IDX_VERBOSITY, IDX_FAST, IDX_LTP_CUT, IDX_WAV49, IDX_LAST }; + +class Codec { + public: + Codec() = default; + ~Codec() { deInitEncoder(); } + bool initEncoder(); + void encodeFrames(uint8_t *data, size_t size); + void deInitEncoder(); + + private: + gsm mGsm = nullptr; +}; + +bool Codec::initEncoder() { + mGsm = gsm_create(); + return mGsm ? true : false; +} + +void Codec::encodeFrames(uint8_t *data, size_t size) { + int32_t verbosity = data[IDX_VERBOSITY] & 0x01; + int32_t fast = data[IDX_FAST] & 0x01; + int32_t ltp_cut = data[IDX_LTP_CUT] & 0x01; + int32_t wav49 = data[IDX_WAV49] & 0x01; + gsm_option(mGsm, GSM_OPT_VERBOSE, &verbosity); + gsm_option(mGsm, GSM_OPT_FAST, &fast); + gsm_option(mGsm, GSM_OPT_LTP_CUT, <p_cut); + gsm_option(mGsm, GSM_OPT_WAV49, &wav49); + data += IDX_LAST; + size -= IDX_LAST; + + while (size > 0) { + gsm_signal tmpData[kGsmInNumSamples]; + gsm_frame out; + size_t frameSize = std::min(size, kGsmInBufferSize); + + memcpy(tmpData, data, frameSize); + if (frameSize < kGsmInBufferSize) { + memset(reinterpret_cast<uint8_t *>(tmpData) + frameSize, data[0], + kGsmInBufferSize - frameSize); + } + gsm_encode(mGsm, tmpData, out); + data += frameSize; + size -= frameSize; + } +} + +void Codec::deInitEncoder() { + if (mGsm) { + gsm_destroy(mGsm); + mGsm = nullptr; + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + if (size < IDX_LAST) { + return 0; + } + Codec *codec = new Codec(); + if (!codec) { + return 0; + } + if (codec->initEncoder()) { + codec->encodeFrames(const_cast<uint8_t *>(data), size); + } + delete codec; + return 0; +} diff --git a/inc/config.h b/inc/config.h index 223c9d4..dfb1ead 100644 --- a/inc/config.h +++ b/inc/config.h @@ -25,7 +25,7 @@ /*efine HAS__FSETMODE 1 /* _fsetmode -- set file mode */ #define HAS_STRING_H 1 /* /usr/include/string.h */ -#define HAS_STRINGS_H 1 /* /usr/include/strings.h */ +/*efine HAS_STRINGS_H 1 /* /usr/include/strings.h */ #define HAS_UNISTD_H 1 /* /usr/include/unistd.h */ #define HAS_UTIME 1 /* POSIX utime(path, times) */ @@ -10,6 +10,10 @@ #define GSM_H #ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus # define NeedFunctionPrototypes 1 #endif @@ -43,7 +47,7 @@ typedef gsm_byte gsm_frame[33]; /* 33 * 8 bits */ #define GSM_MAGIC 0xD /* 13 kbit/s RPE-LTP */ -#define GSM_PATCHLEVEL 18 +#define GSM_PATCHLEVEL 19 #define GSM_MINOR 0 #define GSM_MAJOR 1 @@ -68,4 +72,8 @@ extern void gsm_implode GSM_P((gsm, gsm_signal *, gsm_byte *)); #undef GSM_P +#ifdef __cplusplus +} // extern "C" +#endif + #endif /* GSM_H */ diff --git a/inc/private.h b/inc/private.h index d1b1510..d9bed03 100644 --- a/inc/private.h +++ b/inc/private.h @@ -9,6 +9,10 @@ #ifndef PRIVATE_H #define PRIVATE_H +#ifdef __cplusplus + extern "C" { +#endif + typedef short word; /* 16 bit signed int */ typedef long longword; /* 32 bit signed int */ @@ -266,4 +270,8 @@ extern word gsm_FAC[8]; #include "unproto.h" +#ifdef __cplusplus + } // extern "C" +#endif + #endif /* PRIVATE_H */ diff --git a/inc/toast.h b/inc/toast.h index b42d9ae..847e8d4 100644 --- a/inc/toast.h +++ b/inc/toast.h @@ -11,6 +11,10 @@ #include "config.h" +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif + #include <sys/types.h> #include <sys/stat.h> |