[RESTRICT AUTOMERGE] Updated AdbUtils.java and memutils file
Added functions in AdbUtils.java which enable testing for both hangs and crashes
Updated memutils file to support different configurations
Bug: 147497306
Test: none
Change-Id: I554ac7674317cf203206411b69e6e4ef31883e75
diff --git a/hostsidetests/securitybulletin/AndroidTest.xml b/hostsidetests/securitybulletin/AndroidTest.xml
index 62f866d..8d4203e 100644
--- a/hostsidetests/securitybulletin/AndroidTest.xml
+++ b/hostsidetests/securitybulletin/AndroidTest.xml
@@ -204,6 +204,20 @@
<option name="test-file-name" value="CtsHostLaunchAnyWhereApp.apk" />
</target_preparer>
+ <!-- The following tests hit either 32-bit or 64-bit, but not both. All tests in this -->
+ <!-- section should take care to build either 32 bit or 64 bit binary, but not both. -->
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+
+ <!-- Please add 32-bit binary tests below to avoid merge conflict -->
+
+
+ <!-- Please add 64-bit binary tests below to avoid merge conflict -->
+
+
+ <option name="append-bitness" value="false" />
+ </target_preparer>
+
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="OomCatcher.apk" />
diff --git a/hostsidetests/securitybulletin/securityPatch/includes/memutils.c b/hostsidetests/securitybulletin/securityPatch/includes/memutils.c
new file mode 100644
index 0000000..650d2f6
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/includes/memutils.c
@@ -0,0 +1,267 @@
+/**
+ * Copyright (C) 2019 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.
+ */
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include "memutils.h"
+
+void exit_handler(void) {
+ size_t page_size = getpagesize();
+ for (int i = 0; i < s_mem_map_index; i++) {
+ if (NULL != s_mem_map[i].start_ptr) {
+ ENABLE_MEM_ACCESS(s_mem_map[i].start_ptr,
+ (s_mem_map[i].num_pages * page_size));
+ }
+ }
+#ifdef CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE
+ for (int i = 0; i < MAX_ENTRIES; i++) {
+ if (NULL != s_free_list[i].start_ptr) {
+ ENABLE_MEM_ACCESS(s_free_list[i].start_ptr,
+ (s_free_list[i].num_pages * page_size));
+ real_free(s_free_list[i].start_ptr);
+ memset(&s_free_list[i], 0, sizeof(map_struct_t));
+ }
+ }
+#endif /* CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE */
+}
+
+void sigsegv_handler(int signum, siginfo_t *info, void* context) {
+ exit_handler();
+ (*old_sa.sa_sigaction)(signum, info, context);
+}
+
+void sighandler_init(void) {
+ sigemptyset(&new_sa.sa_mask);
+ new_sa.sa_flags = SA_SIGINFO;
+ new_sa.sa_sigaction = sigsegv_handler;
+ sigaction(SIGSEGV, &new_sa, &old_sa);
+}
+
+void memutils_init(void) {
+ real_memalign = dlsym(RTLD_NEXT, "memalign");
+ if (NULL == real_memalign) {
+ return;
+ }
+ real_calloc = dlsym(RTLD_NEXT, "calloc");
+ if (NULL == real_calloc) {
+ return;
+ }
+ real_malloc = dlsym(RTLD_NEXT, "malloc");
+ if (NULL == real_malloc) {
+ return;
+ }
+ real_realloc = dlsym(RTLD_NEXT, "realloc");
+ if (NULL == real_realloc) {
+ return;
+ }
+ real_free = dlsym(RTLD_NEXT, "free");
+ if (NULL == real_free) {
+ return;
+ }
+ memset(&s_mem_map, 0, MAX_ENTRIES * sizeof(map_struct_t));
+ sighandler_init();
+ atexit(exit_handler);
+ s_memutils_initialized = 1;
+}
+
+void *memalign(size_t alignment, size_t size) {
+ if (s_memutils_initialized == 0) {
+ memutils_init();
+ }
+#ifdef ENABLE_SELECTIVE_OVERLOADING
+ if ((enable_selective_overload & ENABLE_MEMALIGN_CHECK) != ENABLE_MEMALIGN_CHECK) {
+ return real_memalign(alignment, size);
+ }
+#endif /* ENABLE_SELECTIVE_OVERLOADING */
+ char* start_ptr;
+ char* mem_ptr;
+ size_t total_size;
+ size_t aligned_size = size;
+ size_t num_pages;
+ size_t page_size = getpagesize();
+
+ /* User specified alignment is not respected and is overridden by
+ * "new_alignment". This is required to catch OOB read when read offset is
+ * less than user specified alignment. "new_alignment" is derived based on
+ * size_t, and helps to avoid bus errors due to non-aligned memory.
+ * "new_alignment", whenever used, is checked to ensure sizeof(size_t)
+ * has returned proper value */
+ size_t new_alignment = sizeof(size_t);
+
+ if (s_mem_map_index == MAX_ENTRIES) {
+ return real_memalign(alignment, size);
+ }
+
+ if (alignment > page_size) {
+ return real_memalign(alignment, size);
+ }
+
+ if ((0 == page_size) || (0 == alignment) || (0 == size)
+ || (0 == new_alignment)) {
+ return real_memalign(alignment, size);
+ }
+#ifdef CHECK_OVERFLOW
+ if (0 != (size % new_alignment)) {
+ aligned_size = size + (new_alignment - (size % new_alignment));
+ }
+#endif
+
+ if (0 != (aligned_size % page_size)) {
+ num_pages = (aligned_size / page_size) + 2;
+ } else {
+ num_pages = (aligned_size / page_size) + 1;
+ }
+
+ total_size = (num_pages * page_size);
+ start_ptr = (char *) real_memalign(page_size, total_size);
+#ifdef CHECK_OVERFLOW
+#ifdef FORCE_UNALIGN
+ mem_ptr = (char *) start_ptr + ((num_pages - 1) * page_size) - size;
+#else
+ mem_ptr = (char *) start_ptr + ((num_pages - 1) * page_size) - aligned_size;
+#endif /* FORCE_UNALIGN */
+ DISABLE_MEM_ACCESS((start_ptr + ((num_pages - 1) * page_size)), page_size);
+#endif /* CHECK_OVERFLOW */
+#ifdef CHECK_UNDERFLOW
+ mem_ptr = (char *) start_ptr + page_size;
+ DISABLE_MEM_ACCESS(start_ptr, page_size);
+#endif /* CHECK_UNDERFLOW */
+ s_mem_map[s_mem_map_index].start_ptr = start_ptr;
+ s_mem_map[s_mem_map_index].mem_ptr = mem_ptr;
+ s_mem_map[s_mem_map_index].num_pages = num_pages;
+ s_mem_map[s_mem_map_index].mem_size = size;
+ s_mem_map_index++;
+ memset(mem_ptr, INITIAL_VAL, size);
+ return mem_ptr;
+}
+
+void *malloc(size_t size) {
+ if (s_memutils_initialized == 0) {
+ memutils_init();
+ }
+#ifdef ENABLE_SELECTIVE_OVERLOADING
+ if ((enable_selective_overload & ENABLE_MALLOC_CHECK) != ENABLE_MALLOC_CHECK) {
+ return real_malloc(size);
+ }
+#endif /* ENABLE_SELECTIVE_OVERLOADING */
+ return memalign(sizeof(size_t), size);
+}
+
+void *calloc(size_t nitems, size_t size) {
+ if (s_memutils_initialized == 0) {
+ memutils_init();
+ }
+#ifdef ENABLE_SELECTIVE_OVERLOADING
+ if ((enable_selective_overload & ENABLE_CALLOC_CHECK) != ENABLE_CALLOC_CHECK) {
+ return real_calloc(nitems, size);
+ }
+#endif /* ENABLE_SELECTIVE_OVERLOADING */
+ void *ptr = memalign(sizeof(size_t), (nitems * size));
+ if (ptr)
+ memset(ptr, 0, (nitems * size));
+ return ptr;
+}
+
+void *realloc(void *ptr, size_t size) {
+ if (s_memutils_initialized == 0) {
+ memutils_init();
+ }
+#ifdef ENABLE_SELECTIVE_OVERLOADING
+ if ((enable_selective_overload & ENABLE_REALLOC_CHECK) != ENABLE_REALLOC_CHECK) {
+ return real_realloc(ptr, size);
+ }
+#endif /* ENABLE_SELECTIVE_OVERLOADING */
+ if (ptr != NULL) {
+ int i = 0;
+ for (i = 0; i < s_mem_map_index; i++) {
+ if (ptr == s_mem_map[i].mem_ptr) {
+ void* temp = malloc(size);
+ if (temp == NULL) {
+ return NULL;
+ }
+ if (s_mem_map[i].mem_size > size) {
+ memcpy(temp, ptr, size);
+ } else {
+ memcpy(temp, ptr, s_mem_map[i].mem_size);
+ }
+ free(s_mem_map[i].mem_ptr);
+ return temp;
+ }
+ }
+ }
+ return real_realloc(ptr, size);
+}
+
+void free(void *ptr) {
+ if (s_memutils_initialized == 0) {
+ memutils_init();
+ }
+#ifdef ENABLE_SELECTIVE_OVERLOADING
+ if ((enable_selective_overload & ENABLE_FREE_CHECK) != ENABLE_FREE_CHECK) {
+ return real_free(ptr);
+ }
+#endif /* ENABLE_SELECTIVE_OVERLOADING */
+ if (ptr != NULL) {
+ int i = 0;
+ size_t page_size = getpagesize();
+ for (i = 0; i < s_mem_map_index; i++) {
+ if (ptr == s_mem_map[i].mem_ptr) {
+#ifdef CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE
+ s_free_list[s_free_write_index].start_ptr =
+ s_mem_map[i].start_ptr;
+ s_free_list[s_free_write_index].mem_ptr = s_mem_map[i].mem_ptr;
+ s_free_list[s_free_write_index].num_pages =
+ s_mem_map[i].num_pages;
+ s_free_list[s_free_write_index].mem_size = s_mem_map[i].mem_size;
+ s_free_write_index++;
+ s_free_list_size += s_mem_map[i].mem_size;
+ DISABLE_MEM_ACCESS(s_mem_map[i].start_ptr,
+ (s_mem_map[i].num_pages * page_size));
+ memset(&s_mem_map[i], 0, sizeof(map_struct_t));
+ while (s_free_list_size > CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE) {
+ ENABLE_MEM_ACCESS(
+ s_free_list[s_free_read_index].start_ptr,
+ (s_free_list[s_free_read_index].num_pages * page_size));
+ real_free(s_free_list[s_free_read_index].start_ptr);
+ s_free_list_size -= s_free_list[s_free_read_index].mem_size;
+ memset(&s_free_list[s_free_read_index], 0,
+ sizeof(map_struct_t));
+ s_free_read_index++;
+ if ((s_free_read_index == MAX_ENTRIES)
+ || (s_free_read_index >= s_free_write_index)) {
+ break;
+ }
+ }
+ return;
+#else
+ ENABLE_MEM_ACCESS(s_mem_map[i].start_ptr,
+ (s_mem_map[i].num_pages * page_size));
+ real_free(s_mem_map[i].start_ptr);
+ memset(&s_mem_map[i], 0, sizeof(map_struct_t));
+ return;
+#endif /* CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE */
+ }
+ }
+ }
+ real_free(ptr);
+ return;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/includes/memutils.h b/hostsidetests/securitybulletin/securityPatch/includes/memutils.h
new file mode 100644
index 0000000..10ee31e
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/includes/memutils.h
@@ -0,0 +1,68 @@
+/**
+ * Copyright (C) 2019 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.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#define MAX_ENTRIES (1024 * 1024)
+#define INITIAL_VAL (0xBE)
+
+#define DISABLE_MEM_ACCESS(mem, size)\
+ mprotect((char *) mem, size, PROT_NONE);
+
+#define ENABLE_MEM_ACCESS(mem, size)\
+ mprotect((char *) mem, size, PROT_READ | PROT_WRITE);
+
+#define ENABLE_NONE 0x00
+#define ENABLE_MEMALIGN_CHECK 0x01
+#define ENABLE_MALLOC_CHECK 0x02
+#define ENABLE_CALLOC_CHECK 0x04
+#define ENABLE_REALLOC_CHECK 0x08
+#define ENABLE_FREE_CHECK 0x10
+#define ENABLE_ALL ENABLE_MEMALIGN_CHECK | ENABLE_MALLOC_CHECK |\
+ ENABLE_CALLOC_CHECK | ENABLE_REALLOC_CHECK | ENABLE_FREE_CHECK
+
+typedef struct _map_struct_t {
+ void *start_ptr;
+ void *mem_ptr;
+ int num_pages;
+ size_t mem_size;
+} map_struct_t;
+
+static void* (*real_memalign)(size_t, size_t) = NULL;
+static void* (*real_calloc)(size_t, size_t) = NULL;
+static void* (*real_malloc)(size_t) = NULL;
+static void* (*real_realloc)(void *ptr, size_t size) = NULL;
+static void (*real_free)(void *) = NULL;
+static int s_memutils_initialized = 0;
+static int s_mem_map_index = 0;
+static struct sigaction new_sa, old_sa;
+#ifdef ENABLE_SELECTIVE_OVERLOADING
+extern char enable_selective_overload;
+#endif /* ENABLE_SELECTIVE_OVERLOADING */
+#ifdef CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE
+static int s_free_write_index = 0;
+static int s_free_read_index = 0;
+static int s_free_list_size = 0;
+map_struct_t s_free_list[MAX_ENTRIES];
+#endif /* CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE */
+map_struct_t s_mem_map[MAX_ENTRIES];
+#if (!(defined CHECK_OVERFLOW) && !(defined CHECK_UNDERFLOW))
+ #error "CHECK MACROS NOT DEFINED"
+#endif
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
diff --git a/hostsidetests/securitybulletin/securityPatch/includes/omxUtils.cpp b/hostsidetests/securitybulletin/securityPatch/includes/omxUtils.cpp
index 85b8422..ac28dba 100644
--- a/hostsidetests/securitybulletin/securityPatch/includes/omxUtils.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/includes/omxUtils.cpp
@@ -24,6 +24,7 @@
int32_t mLastMsgGeneration;
int32_t mCurGeneration;
List<omx_message> mMessageQueue;
+int numCallbackEmptyBufferDone;
struct CodecObserver : public BnOMXObserver {
public:
@@ -42,7 +43,11 @@
Mutex::Autolock autoLock(mLock);
for (std::list<omx_message>::const_iterator it = messages.cbegin();
it != messages.cend();) {
- mMessageQueue.push_back(*it++);
+ mMessageQueue.push_back(*it);
+ const omx_message &msg = *it++;
+ if (msg.type == omx_message::EMPTY_BUFFER_DONE) {
+ numCallbackEmptyBufferDone++;
+ }
mLastMsgGeneration = gen;
}
mMessageAddedCondition.signal();
@@ -51,6 +56,22 @@
handleMessages(mGeneration, messages);
}
+struct DeathNotifier : public IBinder::DeathRecipient,
+ public ::android::hardware::hidl_death_recipient {
+ explicit DeathNotifier() {
+ }
+ virtual void binderDied(const wp<IBinder> &) {
+ ALOGE("Binder Died");
+ exit (EXIT_FAILURE);
+ }
+ virtual void serviceDied(
+ uint64_t /* cookie */,
+ const wp<::android::hidl::base::V1_0::IBase>& /* who */) {
+ ALOGE("Service Died");
+ exit (EXIT_FAILURE);
+ }
+};
+sp<DeathNotifier> mDeathNotifier;
status_t dequeueMessageForNode(omx_message *msg, int64_t timeoutUs) {
int64_t finishBy = ALooper::GetNowUs() + timeoutUs;
status_t err = OK;
@@ -98,7 +119,19 @@
}
mOMX = new utils::LWOmx(tOmx);
sp<CodecObserver> observer = new CodecObserver(++mCurGeneration);
- return mOMX->allocateNode(codecName, observer, &mOMXNode);
+ status_t ret = mOMX->allocateNode(codecName, observer, &mOMXNode);
+ if (ret == OK) {
+ mDeathNotifier = new DeathNotifier();
+ auto tOmxNode = mOMXNode->getHalInterface();
+ if (tOmxNode != NULL) {
+ tOmxNode->linkToDeath(mDeathNotifier, 0);
+ } else {
+ ALOGE("No HAL Interface");
+ exit (EXIT_FAILURE);
+ }
+ }
+ numCallbackEmptyBufferDone = 0;
+ return ret;
}
status_t omxUtilsGetParameter(int portIndex,
OMX_PARAM_PORTDEFINITIONTYPE *params) {
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
index bc71522..2b865e1 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
@@ -34,6 +34,9 @@
import java.util.regex.Pattern;
import java.util.concurrent.TimeUnit;
import java.util.Scanner;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.concurrent.Callable;
import org.json.JSONArray;
import org.json.JSONException;
@@ -46,6 +49,10 @@
public class AdbUtils {
+ final static String TMP_PATH = "/data/local/tmp/";
+ final static int TIMEOUT_SEC = 9 * 60;
+ final static String RESOURCE_ROOT = "/";
+
/** Runs a commandline on the specified device
*
* @param command the command to be ran
@@ -217,6 +224,40 @@
}
}
+ /**
+ * Pushes the specified files to the specified destination directory
+ *
+ * @param inputFiles files required as input
+ * @param inputFilesDestination destination directory to which input files are
+ * pushed
+ * @param device device to be run on
+ */
+ public static void pushResources(String[] inputFiles, String inputFilesDestination,
+ ITestDevice device) throws Exception {
+ if ( (inputFiles != null) && (inputFilesDestination != null)) {
+ for (String tempFile : inputFiles) {
+ pushResource(RESOURCE_ROOT + tempFile, inputFilesDestination + tempFile, device);
+ }
+ }
+ }
+
+ /**
+ * Removes the specified files from the specified destination directory
+ *
+ * @param inputFiles files required as input
+ * @param inputFilesDestination destination directory where input files are
+ * present
+ * @param device device to be run on
+ */
+ public static void removeResources(String[] inputFiles, String inputFilesDestination,
+ ITestDevice device) throws Exception {
+ if ( (inputFiles != null) && (inputFilesDestination != null)) {
+ for (String tempFile : inputFiles) {
+ runCommandLine("rm " + inputFilesDestination + tempFile, device);
+ }
+ }
+ }
+
/**
* Extracts the binary data from a resource and writes it to a temp file
*/
@@ -277,9 +318,22 @@
*/
public static int runPocGetExitStatus(String pocName, ITestDevice device, int timeout)
throws Exception {
- device.executeShellCommand("chmod +x /data/local/tmp/" + pocName);
+ return runPocGetExitStatus(pocName, null, device, timeout);
+ }
+
+ /**
+ * Pushes and runs a binary to the device and returns the exit status.
+ * @param pocName a string path to poc from the /res folder
+ * @param arguments input arguments for the poc
+ * @param device device to be ran on
+ * @param timeout time to wait for output in seconds
+
+ */
+ public static int runPocGetExitStatus(String pocName, String arguments, ITestDevice device,
+ int timeout) throws Exception {
+ device.executeShellCommand("chmod +x " + TMP_PATH + pocName);
CollectingOutputReceiver receiver = new CollectingOutputReceiver();
- String cmd = "/data/local/tmp/" + pocName + " > /dev/null 2>&1; echo $?";
+ String cmd = TMP_PATH + pocName + " " + arguments + " > /dev/null 2>&1; echo $?";
long time = System.currentTimeMillis();
device.executeShellCommand(cmd, receiver, timeout, TimeUnit.SECONDS, 0);
time = System.currentTimeMillis() - time;
@@ -301,8 +355,20 @@
*/
public static void runPocAssertExitStatusNotVulnerable(
String pocName, ITestDevice device, int timeout) throws Exception {
+ runPocAssertExitStatusNotVulnerable(pocName, null, device, timeout);
+ }
+
+ /**
+ * Pushes and runs a binary and asserts that the exit status isn't 113: vulnerable.
+ * @param pocName a string path to poc from the /res folder
+ * @param arguments input arguments for the poc
+ * @param device device to be ran on
+ * @param timeout time to wait for output in seconds
+ */
+ public static void runPocAssertExitStatusNotVulnerable(String pocName, String arguments,
+ ITestDevice device, int timeout) throws Exception {
assertTrue("PoC returned exit status 113: vulnerable",
- runPocGetExitStatus(pocName, device, timeout) != 113);
+ runPocGetExitStatus(pocName, arguments, device, timeout) != 113);
}
public static int runProxyAutoConfig(String pacName, ITestDevice device) throws Exception {
@@ -329,6 +395,99 @@
}
/**
+ * Runs the poc binary and asserts following 2 conditions.
+ * 1. There are no security crashes in the binary.
+ * 2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
+ *
+ * @param binaryName name of the binary
+ * @param arguments arguments for running the binary
+ * @param device device to be run on
+ */
+ public static void runPocAssertNoCrashesNotVulnerable(String binaryName, String arguments,
+ ITestDevice device) throws Exception {
+ runPocAssertNoCrashesNotVulnerable(binaryName, arguments, null, null, device, null);
+ }
+
+ /**
+ * Runs the poc binary and asserts following 2 conditions.
+ * 1. There are no security crashes in the binary.
+ * 2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
+ *
+ * @param binaryName name of the binary
+ * @param arguments arguments for running the binary
+ * @param device device to be run on
+ * @param processPatternStrings a Pattern string to match the crash tombstone
+ * process
+ */
+ public static void runPocAssertNoCrashesNotVulnerable(String binaryName, String arguments,
+ ITestDevice device, String processPatternStrings[]) throws Exception {
+ runPocAssertNoCrashesNotVulnerable(binaryName, arguments, null, null, device,
+ processPatternStrings);
+ }
+
+ /**
+ * Runs the poc binary and asserts following 2 conditions.
+ * 1. There are no security crashes in the binary.
+ * 2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
+ *
+ * @param binaryName name of the binary
+ * @param arguments arguments for running the binary
+ * @param inputFiles files required as input
+ * @param inputFilesDestination destination directory to which input files are
+ * pushed
+ * @param device device to be run on
+ */
+ public static void runPocAssertNoCrashesNotVulnerable(String binaryName, String arguments,
+ String inputFiles[], String inputFilesDestination, ITestDevice device)
+ throws Exception {
+ runPocAssertNoCrashesNotVulnerable(binaryName, arguments, inputFiles, inputFilesDestination,
+ device, null);
+ }
+
+ /**
+ * Runs the poc binary and asserts following 3 conditions.
+ * 1. There are no security crashes in the binary.
+ * 2. There are no security crashes that match the expected process pattern.
+ * 3. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
+ *
+ * @param binaryName name of the binary
+ * @param arguments arguments for running the binary
+ * @param inputFiles files required as input
+ * @param inputFilesDestination destination directory to which input files are
+ * pushed
+ * @param device device to be run on
+ * @param processPatternStrings a Pattern string to match the crash tombstone
+ * process
+ */
+ public static void runPocAssertNoCrashesNotVulnerable(String binaryName, String arguments,
+ String inputFiles[], String inputFilesDestination, ITestDevice device,
+ String processPatternStrings[]) throws Exception {
+ pushResources(inputFiles, inputFilesDestination, device);
+ runCommandLine("logcat -c", device);
+ try {
+ runPocAssertExitStatusNotVulnerable(binaryName, arguments, device, TIMEOUT_SEC);
+ } catch (IllegalArgumentException e) {
+ /*
+ * Since 'runPocGetExitStatus' method raises IllegalArgumentException upon
+ * hang/timeout, catching the exception here and ignoring it. Hangs are of
+ * Moderate severity and hence patches may not be ported. This piece of code can
+ * be removed once 'runPocGetExitStatus' is updated to handle hangs.
+ */
+ CLog.w("Ignoring IllegalArgumentException: " + e);
+ } finally {
+ removeResources(inputFiles, inputFilesDestination, device);
+ }
+ List<String> processPatternList = new ArrayList<>();
+ if (processPatternStrings != null) {
+ processPatternList.addAll(Arrays.asList(processPatternStrings));
+ }
+ processPatternList.add(binaryName);
+ String[] processPatternStringsWithSelf = new String[processPatternList.size()];
+ processPatternList.toArray(processPatternStringsWithSelf);
+ assertNoCrashes(device, processPatternStringsWithSelf);
+ }
+
+ /**
* Dumps logcat and asserts that there are no security crashes that match the expected process.
* By default, checks min crash addresses
* pattern. Ensure that adb logcat -c is called beforehand.
@@ -378,39 +537,4 @@
}
fail(error.toString());
}
-
- /**
- * Executes a given poc within a given timeout. Returns error if the
- * given poc doesnt complete its execution within timeout. It also deletes
- * the list of files provided.
- *
- * @param runner the thread which will be run
- * @param timeout the timeout within which the thread's execution should
- * complete
- * @param device device to be ran on
- * @param inputFiles list of files to be deleted
- */
- public static void runWithTimeoutDeleteFiles(Runnable runner, int timeout, ITestDevice device,
- String[] inputFiles) throws Exception {
- Thread t = new Thread(runner);
- t.start();
- boolean test_failed = false;
- try {
- t.join(timeout);
- } catch (InterruptedException e) {
- test_failed = true;
- } finally {
- if (inputFiles != null) {
- for (String tempFile : inputFiles) {
- AdbUtils.runCommandLine("rm /data/local/tmp/" + tempFile, device);
- }
- }
- if (test_failed) {
- fail("PoC was interrupted");
- }
- }
- if (t.isAlive()) {
- Assert.fail("PoC not completed within timeout of " + timeout + " ms");
- }
- }
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
index ecc086c..4dcb055 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
@@ -24,61 +24,27 @@
@SecurityTest
public class TestMedia extends SecurityTestCase {
- final static int TIMEOUT_SEC = 9 * 60;
- final static String RESOURCE_ROOT = "/";
- final static String TMP_FILE_PATH = "/data/local/tmp/";
- /****************************************************************
- * To prevent merge conflicts, add tests for N below this comment,
- * before any existing test methods
- ****************************************************************/
+ /******************************************************************************
+ * To prevent merge conflicts, add tests for N below this comment, before any
+ * existing test methods
+ ******************************************************************************/
- /****************************************************************
- * To prevent merge conflicts, add tests for O below this comment,
- * before any existing test methods
- ****************************************************************/
+ /******************************************************************************
+ * To prevent merge conflicts, add tests for O below this comment, before any
+ * existing test methods
+ ******************************************************************************/
- /****************************************************************
- * To prevent merge conflicts, add tests for P below this comment,
- * before any existing test methods
- ****************************************************************/
+ /******************************************************************************
+ * To prevent merge conflicts, add tests for P below this comment, before any
+ * existing test methods
+ ******************************************************************************/
- /**
- * Pushes input files, runs the PoC and checks for crash and hang
- *
- * @param binaryName name of the binary
- * @param inputFiles files required as input
- * @param arguments arguments for running the binary
- * @param device device to be run on
- * @param errPattern error patterns to be checked for
- */
- public static void runMediaTest(String binaryName,
- String inputFiles[], String arguments, ITestDevice device,
- String processPatternStrings[]) throws Exception {
- if (inputFiles != null) {
- for (String tempFile : inputFiles) {
- AdbUtils.pushResource(RESOURCE_ROOT + tempFile,
- TMP_FILE_PATH + tempFile, device);
- }
- }
- AdbUtils.runCommandLine("logcat -c", device);
- AdbUtils.runWithTimeoutDeleteFiles(new Runnable() {
- @Override
- public void run() {
- try {
- AdbUtils.runPocNoOutput(binaryName, device,
- TIMEOUT_SEC + 30, arguments);
- } catch (Exception e) {
- CLog.w("Exception: " + e.getMessage());
- }
- }
- }, TIMEOUT_SEC * 1000, device, inputFiles);
- AdbUtils.assertNoCrashes(device, binaryName);
- if (processPatternStrings != null) {
- AdbUtils.assertNoCrashes(device, processPatternStrings);
- }
- }
+ /******************************************************************************
+ * To prevent merge conflicts, add tests for Q below this comment, before any
+ * existing test methods
+ ******************************************************************************/
}