Merge "Added timedtext_fuzzer" am: 2fb39f8cc5 am: 866ca5990f
Original change: https://android-review.googlesource.com/c/platform/frameworks/av/+/2251233
Change-Id: I3e3ec3e72985121108f3a368343d3d8dcfee7a64
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/media/libstagefright/timedtext/test/fuzzer/Android.bp b/media/libstagefright/timedtext/test/fuzzer/Android.bp
new file mode 100644
index 0000000..6590ebb
--- /dev/null
+++ b/media/libstagefright/timedtext/test/fuzzer/Android.bp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+cc_library_static {
+ name: "timedtext_fuzz-protos",
+
+ srcs: ["timedtext_fuzz.proto"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: ["libprotobuf-cpp-full"],
+ proto: {
+ type: "full",
+ canonical_path_from_root: false,
+ local_include_dirs: ["."],
+ export_proto_headers: true,
+ },
+}
+
+cc_fuzz {
+ name: "timedtext_fuzzer",
+ srcs: [
+ "timedtext_fuzzer.cpp",
+ ],
+ static_libs: [
+ "libstagefright_timedtext",
+ "timedtext_fuzz-protos",
+ ],
+ shared_libs: [
+ "libstagefright_foundation",
+ "libprotobuf-cpp-full",
+ "libbinder",
+ "libprotobuf-mutator",
+ ],
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 155276,
+ },
+}
diff --git a/media/libstagefright/timedtext/test/fuzzer/README.md b/media/libstagefright/timedtext/test/fuzzer/README.md
new file mode 100644
index 0000000..f391ea7
--- /dev/null
+++ b/media/libstagefright/timedtext/test/fuzzer/README.md
@@ -0,0 +1,23 @@
+# Fuzzer for libstagefright_timedtext
+
+libstagefright_timedtext supports the following parameters:
+1. Flags (parameter name: `flags`)
+2. TimeMs (parameter name: `timeMs`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `flags` | 1. `TextDescriptions::OUT_OF_BAND_TEXT_SRT` 2. `TextDescriptions::GLOBAL_DESCRIPTIONS` 3. `TextDescriptions::IN_BAND_TEXT_3GPP` 4. `TextDescriptions::LOCAL_DESCRIPTIONS` | Value chosen from valid values by obtaining index from FuzzedDataProvider|
+| `timeMs` | `INT_MIN` to `INT_MAX` | Value obtained from FuzzedDataProvider|
+
+
+#### Steps to run
+
+1. Build the fuzzer
+```
+ $ mm -j$(nproc) timedtext_fuzzer
+```
+2. Run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/timedtext_fuzzer/timedtext_fuzzer
+```
diff --git a/media/libstagefright/timedtext/test/fuzzer/timedtext_fuzz.proto b/media/libstagefright/timedtext/test/fuzzer/timedtext_fuzz.proto
new file mode 100644
index 0000000..4c90278
--- /dev/null
+++ b/media/libstagefright/timedtext/test/fuzzer/timedtext_fuzz.proto
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+/*
+ * proto files are used for Structure Aware fuzzing so that fuzzing can be
+ * made more effective.
+ * timedtext_fuzz.proto is used to declare structures, which are used
+ * purely inside timedtext_fuzzer.
+ */
+
+syntax = "proto3";
+
+enum Flag {
+ flag3gppglobal = 0;
+ flag3gpplocal = 1;
+ flagsrtlocal = 2;
+}
+
+enum ChunkType {
+ default = 0;
+ tx3g = 1954034535;
+ styl = 1937013100;
+ krok = 1802661739;
+ hlit = 1751935348;
+ hclr = 1751346290;
+ dlay = 1684824441;
+ href = 1752327526;
+ tbox = 1952608120;
+ blnk = 1651273323;
+ txrp = 1953985136;
+}
+
+message FontRecord {
+ uint32 fontId = 1;
+ repeated uint32 font = 2;
+}
+
+message SRTLocal {
+ repeated uint32 data = 1;
+}
+
+message GPPGlobal {
+ uint64 reservedBytes = 1;
+ uint32 displayFlags = 2;
+ int32 horizontal_vertical_justification = 3;
+ uint32 rgba = 4;
+ int32 textBox = 5;
+ uint32 styleRecordStart = 6;
+ uint32 fontId = 7;
+ uint32 fontStyle = 8;
+ uint32 entryCount = 9;
+ repeated FontRecord fontEntry = 10;
+ uint32 defaultDisparity = 11;
+}
+
+message StyleRecord {
+ uint32 startchar = 1;
+ uint32 font = 2;
+ uint32 rgba = 3;
+}
+
+message TextStyleBox {
+ uint32 count = 1;
+ repeated StyleRecord record = 2;
+}
+
+message HighlightBox {
+ uint32 start = 1;
+ uint32 end = 2;
+}
+
+message HighlightColor {
+ uint32 rgba = 1;
+}
+
+message TextKaraokeBox {
+ uint32 highlightStartTime = 1;
+ uint32 entryCount = 2;
+ repeated uint64 highlightData = 3;
+}
+
+message BoxRecord {
+ uint32 topleft = 1;
+ uint32 bottomright = 2;
+}
+
+message BlinkBox {
+ uint32 charoffset = 1;
+}
+
+message HyperTextBox {
+ uint32 charoffset = 1;
+ uint32 urlLength = 2;
+ repeated uint32 url = 3;
+ uint32 altLength = 4;
+ repeated uint32 altString = 5;
+}
+
+message GPPLocalText {
+ string text = 1;
+}
+
+message GPPLocalFormat {
+ uint64 reservedBytes = 1;
+ oneof formatStyle {
+ TextStyleBox textbox = 2;
+ HighlightBox hltbox = 3;
+ HighlightColor hltcolor = 4;
+ TextKaraokeBox krokbox = 5;
+ uint32 scrollDelay = 6;
+ HyperTextBox hrefBox = 7;
+ BoxRecord boxrecord = 8;
+ BlinkBox blinkBox = 9;
+ uint32 wrapFlag = 10;
+ }
+}
+
+message GPPLocal {
+ GPPLocalText localtext = 1;
+ GPPLocalFormat format = 2;
+}
+
+message TimedText {
+ Flag handle = 1;
+ int32 timeMs = 2;
+ SRTLocal srt = 3;
+ GPPGlobal global = 4;
+ GPPLocal local = 5;
+}
diff --git a/media/libstagefright/timedtext/test/fuzzer/timedtext_fuzzer.cpp b/media/libstagefright/timedtext/test/fuzzer/timedtext_fuzzer.cpp
new file mode 100644
index 0000000..da1bdf8
--- /dev/null
+++ b/media/libstagefright/timedtext/test/fuzzer/timedtext_fuzzer.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2022 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 <binder/Parcel.h>
+#include <timedtext/TextDescriptions.h>
+#include <timedtext_fuzz.pb.h>
+#include "fuzzer/FuzzedDataProvider.h"
+#include "src/libfuzzer/libfuzzer_macro.h"
+
+using namespace android;
+constexpr int32_t kTextBytes = 2;
+constexpr int32_t kChunkBytes = 8;
+constexpr int32_t kChunkTypeBytes = 4;
+constexpr int32_t kGlobalTextOffset = 0;
+constexpr size_t kByte3Mask = 0xff000000UL;
+constexpr size_t kByte2Mask = 0x00ff0000UL;
+constexpr size_t kByte1Mask = 0x0000ff00UL;
+constexpr size_t kByte0Mask = 0x000000ffUL;
+
+/**
+ * Sets ChunkSize/ChunkType (uint32_t) in timedtext-description vector<uint8_t>
+ * by extracting each byte from ChunkSize and populating the vector.
+ */
+void setChunkParameter(std::vector<uint8_t>& timedtext, size_t param, size_t paramOffset) {
+ timedtext[paramOffset + 0] = (param & kByte3Mask) >> 24;
+ timedtext[paramOffset + 1] = (param & kByte2Mask) >> 16;
+ timedtext[paramOffset + 2] = (param & kByte1Mask) >> 8;
+ timedtext[paramOffset + 3] = (param & kByte0Mask);
+}
+
+/**
+ * Sets TextLength(uint16_t) in 3GPPLocal-description vector<uint8_t>
+ * by extracting each byte from TextLength and populating the vector.
+ */
+void setTextSize(std::vector<uint8_t>& local3GPPDescription, int32_t textLength) {
+ local3GPPDescription[0] = (textLength & kByte1Mask) >> 8;
+ local3GPPDescription[1] = (textLength & kByte0Mask);
+}
+
+DEFINE_PROTO_FUZZER(const TimedText& input) {
+ switch (input.handle()) {
+ case flag3gppglobal: {
+ size_t gppGlobalByteSize = input.global().ByteSizeLong();
+ if (gppGlobalByteSize) {
+ std::vector<uint8_t> global3GPPDescription(gppGlobalByteSize + kChunkBytes);
+ setChunkParameter(global3GPPDescription, gppGlobalByteSize, kGlobalTextOffset);
+ setChunkParameter(global3GPPDescription, tx3g, kGlobalTextOffset + kChunkTypeBytes);
+ input.global().SerializeToArray(global3GPPDescription.data() + kChunkBytes,
+ global3GPPDescription.size());
+ Parcel* parcel = new Parcel();
+ TextDescriptions::getParcelOfDescriptions(
+ global3GPPDescription.data(), global3GPPDescription.size(),
+ TextDescriptions::IN_BAND_TEXT_3GPP | TextDescriptions::GLOBAL_DESCRIPTIONS,
+ input.timems(), parcel);
+ delete parcel;
+ }
+ break;
+ }
+ case flag3gpplocal: {
+ size_t gppLocalByteSize = input.local().ByteSizeLong();
+ if (gppLocalByteSize) {
+ std::vector<uint8_t> local3GPPDescription(gppLocalByteSize + kChunkBytes +
+ kTextBytes);
+ std::string text = input.local().localtext().text();
+ int32_t textLength = text.size();
+ setTextSize(local3GPPDescription, textLength);
+ input.local().localtext().SerializeToArray(local3GPPDescription.data() + kTextBytes,
+ textLength);
+ size_t gppLocalFormatSize = input.local().format().ByteSizeLong();
+ size_t textOffset = textLength + kTextBytes;
+ setChunkParameter(local3GPPDescription, gppLocalFormatSize, textOffset);
+ switch (input.local().format().formatStyle_case()) {
+ case GPPLocalFormat::FormatStyleCase::kTextbox: {
+ setChunkParameter(local3GPPDescription, styl, textOffset + kChunkTypeBytes);
+ input.local().format().SerializeToArray(
+ local3GPPDescription.data() + textOffset + kChunkBytes,
+ gppLocalFormatSize);
+ break;
+ }
+ case GPPLocalFormat::FormatStyleCase::kHltbox: {
+ setChunkParameter(local3GPPDescription, hlit, textOffset + kChunkTypeBytes);
+ input.local().format().SerializeToArray(
+ local3GPPDescription.data() + textOffset + kChunkBytes,
+ gppLocalFormatSize);
+ break;
+ }
+ case GPPLocalFormat::FormatStyleCase::kHltcolor: {
+ setChunkParameter(local3GPPDescription, hclr, textOffset + kChunkTypeBytes);
+ input.local().format().SerializeToArray(
+ local3GPPDescription.data() + textOffset + kChunkBytes,
+ gppLocalFormatSize);
+ break;
+ }
+ case GPPLocalFormat::FormatStyleCase::kKrokbox: {
+ setChunkParameter(local3GPPDescription, krok, textOffset + kChunkTypeBytes);
+ input.local().format().SerializeToArray(
+ local3GPPDescription.data() + textOffset + kChunkBytes,
+ gppLocalFormatSize);
+ break;
+ }
+ case GPPLocalFormat::FormatStyleCase::kScrollDelay: {
+ setChunkParameter(local3GPPDescription, dlay, textOffset + kChunkTypeBytes);
+ input.local().format().SerializeToArray(
+ local3GPPDescription.data() + textOffset + kChunkBytes,
+ gppLocalFormatSize);
+ break;
+ }
+ case GPPLocalFormat::FormatStyleCase::kHrefBox: {
+ setChunkParameter(local3GPPDescription, href, textOffset + kChunkTypeBytes);
+ input.local().format().SerializeToArray(
+ local3GPPDescription.data() + textOffset + kChunkBytes,
+ gppLocalFormatSize);
+ break;
+ }
+ case GPPLocalFormat::FormatStyleCase::kBoxrecord: {
+ setChunkParameter(local3GPPDescription, tbox, textOffset + kChunkTypeBytes);
+ input.local().format().SerializeToArray(
+ local3GPPDescription.data() + textOffset + kChunkBytes,
+ gppLocalFormatSize);
+ break;
+ }
+ case GPPLocalFormat::FormatStyleCase::kBlinkBox: {
+ setChunkParameter(local3GPPDescription, blnk, textOffset + kChunkTypeBytes);
+ input.local().format().SerializeToArray(
+ local3GPPDescription.data() + textOffset + kChunkBytes,
+ gppLocalFormatSize);
+ break;
+ }
+ case GPPLocalFormat::FormatStyleCase::kWrapFlag: {
+ setChunkParameter(local3GPPDescription, txrp, textOffset + kChunkTypeBytes);
+ input.local().format().SerializeToArray(
+ local3GPPDescription.data() + textOffset + kChunkBytes,
+ gppLocalFormatSize);
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ Parcel* parcel = new Parcel();
+ TextDescriptions::getParcelOfDescriptions(
+ local3GPPDescription.data(), local3GPPDescription.size(),
+ TextDescriptions::IN_BAND_TEXT_3GPP | TextDescriptions::LOCAL_DESCRIPTIONS,
+ input.timems(), parcel);
+ delete parcel;
+ }
+ break;
+ }
+ case flagsrtlocal: {
+ size_t srtByteSize = input.srt().ByteSizeLong();
+ if (srtByteSize) {
+ std::vector<uint8_t> srtLocalDescription(srtByteSize);
+ input.srt().SerializeToArray(srtLocalDescription.data(),
+ srtLocalDescription.size());
+ Parcel* parcel = new Parcel();
+ TextDescriptions::getParcelOfDescriptions(
+ srtLocalDescription.data(), srtLocalDescription.size(),
+ TextDescriptions::OUT_OF_BAND_TEXT_SRT |
+ TextDescriptions::LOCAL_DESCRIPTIONS,
+ input.timems(), parcel);
+ delete parcel;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}