Merge "Added timedtext_fuzzer" am: 2fb39f8cc5

Original change: https://android-review.googlesource.com/c/platform/frameworks/av/+/2251233

Change-Id: Ic8079d5f38f362979670508054a1edb230bda564
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;
+    }
+}