1 /*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <jni.h>
18 #include <linux/futex.h>
19 #include <sys/types.h>
20 #include <sys/syscall.h>
21 #include <unistd.h>
22 #include <sys/prctl.h>
23 #include <sys/ptrace.h>
24 #include <sys/wait.h>
25 #include <signal.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/mman.h>
29 #include <sys/stat.h>
30 #include <sys/utsname.h>
31 #include <fcntl.h>
32 #include <cutils/log.h>
33 #include <linux/perf_event.h>
34 #include <errno.h>
35 #include <inttypes.h>
36 #include <arpa/inet.h>
37 #include <linux/ipc.h>
38 #include <pthread.h>
39
40 /*
41 * Returns true iff this device is vulnerable to CVE-2013-2094.
42 * A patch for CVE-2013-2094 can be found at
43 * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=8176cced706b5e5d15887584150764894e94e02f
44 */
android_security_cts_NativeCodeTest_doPerfEventTest(JNIEnv * env,jobject thiz)45 static jboolean android_security_cts_NativeCodeTest_doPerfEventTest(JNIEnv* env, jobject thiz)
46 {
47 uint64_t attr[10] = { 0x4800000001, (uint32_t) -1, 0, 0, 0, 0x300 };
48
49 int fd = syscall(__NR_perf_event_open, attr, 0, -1, -1, 0);
50 jboolean result = (fd != -1);
51
52 if (fd != -1) {
53 close(fd);
54 }
55
56 return result;
57 }
58
59 /*
60 * Detects if the following patch is present.
61 * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c95eb3184ea1a3a2551df57190c81da695e2144b
62 *
63 * Returns true if the patch is applied, or crashes the system otherwise.
64 *
65 * While you're at it, you want to apply the following patch too.
66 * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=b88a2595b6d8aedbd275c07dfa784657b4f757eb
67 * This test doesn't cover the above patch. TODO write a new test.
68 *
69 * Credit: https://github.com/deater/perf_event_tests/blob/master/exploits/arm_perf_exploit.c
70 */
android_security_cts_NativeCodeTest_doPerfEventTest2(JNIEnv * env,jobject thiz)71 static jboolean android_security_cts_NativeCodeTest_doPerfEventTest2(JNIEnv* env, jobject thiz)
72 {
73 struct perf_event_attr pe[2];
74 int fd[2];
75 memset(pe, 0, sizeof(pe));
76 pe[0].type = 2;
77 pe[0].config = 72;
78 pe[0].size = 80;
79 pe[1].type = PERF_TYPE_RAW;
80 pe[1].size = 80;
81 fd[0]=syscall(__NR_perf_event_open, &pe[0], 0, 0, -1, 0);
82 fd[1]=syscall(__NR_perf_event_open, &pe[1], 0, 0, fd[0], 0);
83 close(fd[0]);
84 close(fd[1]);
85 return true;
86 }
87
mmap_syscall(void * addr,size_t len,int prot,int flags,int fd,off_t offset)88 static void* mmap_syscall(void* addr, size_t len, int prot, int flags, int fd, off_t offset)
89 {
90 #ifdef __LP64__
91 return mmap(addr, len, prot, flags, fd, offset);
92 #else
93 return (void*) syscall(__NR_mmap2, addr, len, prot, flags, fd, offset);
94 #endif
95 }
96
97 #define KBASE_REG_COOKIE_TB 2
98 #define KBASE_REG_COOKIE_MTP 3
99
100 /*
101 * Returns true if the device is immune to CVE-2014-1710,
102 * false if the device is vulnerable.
103 */
android_security_cts_NativeCodeTest_doCVE20141710Test(JNIEnv *,jobject)104 static jboolean android_security_cts_NativeCodeTest_doCVE20141710Test(JNIEnv*, jobject)
105 {
106 jboolean result = false;
107 int fd = open("/dev/mali0", O_RDWR);
108 if (fd < 0) {
109 return true; /* not vulnerable */
110 }
111
112 void* a = mmap_syscall(NULL, 0x1000, PROT_READ, MAP_SHARED, fd, KBASE_REG_COOKIE_MTP);
113 void* b = mmap_syscall(NULL, 0x1000, PROT_READ, MAP_SHARED, fd, KBASE_REG_COOKIE_TB);
114
115 if (a == MAP_FAILED) {
116 result = true; /* assume not vulnerable */
117 goto done;
118 }
119
120 if (b == MAP_FAILED) {
121 result = true; /* assume not vulnerable */
122 goto done;
123 }
124
125 /* mprotect should return an error if not vulnerable */
126 result = (mprotect(b, 0x1000, PROT_READ | PROT_WRITE) == -1);
127
128 done:
129 if (a != MAP_FAILED) {
130 munmap(a, 0x1000);
131 }
132 if (b != MAP_FAILED) {
133 munmap(b, 0x1000);
134 }
135 close(fd);
136 return result;
137 }
138
futex_syscall(volatile int * uaddr,int op,int val,const struct timespec * ts,volatile int * uaddr2,int val3)139 static inline int futex_syscall(volatile int* uaddr, int op, int val, const struct timespec* ts,
140 volatile int* uaddr2, int val3) {
141 return syscall(__NR_futex, uaddr, op, val, ts, uaddr2, val3);
142 }
143
144 /*
145 * Test for vulnerability to CVE-2014-3153, a bug in the futex() syscall that can
146 * lead to privilege escalation and was used by the towelroot exploit. Returns true
147 * if device is patched, false if still vulnerable.
148 */
android_security_cts_NativeCodeTest_doFutexTest(JNIEnv *,jobject)149 static jboolean android_security_cts_NativeCodeTest_doFutexTest(JNIEnv*, jobject)
150 {
151 jboolean result = false;
152
153 int futex = 1;
154 int ret;
155
156 /* The patch will reject FUTEX_CMP_REQUEUE_PI calls where addr == addr2, so
157 * that's what we're checking for - they're both &futex. Patched systems will
158 * return -1 and set errno to 22 (EINVAL), vulnerable systems will return 0.
159 */
160 ret = futex_syscall(&futex, FUTEX_CMP_REQUEUE_PI, 1, NULL, &futex, 0);
161 return (ret == -1 && errno == EINVAL);
162 }
163
android_security_cts_NativeCodeTest_doNvmapIocFromIdTest(JNIEnv *,jobject)164 static jboolean android_security_cts_NativeCodeTest_doNvmapIocFromIdTest(JNIEnv*, jobject)
165 {
166 /*
167 * IOCTL code specified from the original notification.
168 * Also available in:
169 * .../kernel/tegra/drivers/video/tegra/nvmap/nvmap_ioctl.h
170 * #define NVMAP_IOC_MAGIC 'N'
171 * #define NVMAP_IOC_FROM_ID _IOWR(NVMAP_IOC_MAGIC, 2, struct nvmap_create_handle)
172 */
173 const int NVMAP_IOC_FROM_ID = 0xc0084e02;
174 int nvmap = open("/dev/nvmap", O_RDWR | O_CLOEXEC, 0);
175 bool vulnerable = false;
176
177 if (nvmap >= 0) {
178 if (0 == ioctl(nvmap, NVMAP_IOC_FROM_ID)) {
179 /* IOCTL succeeded */
180 vulnerable = true;
181 }
182 else if (errno != ENOTTY) {
183 /* IOCTL failed, but provided the wrong error number */
184 vulnerable = true;
185 }
186
187 close(nvmap);
188 }
189
190 return !vulnerable;
191 }
192
android_security_cts_NativeCodeTest_doPingPongRootTest(JNIEnv *,jobject)193 static jboolean android_security_cts_NativeCodeTest_doPingPongRootTest(JNIEnv*, jobject)
194 {
195 int icmp_sock;
196 struct sockaddr sock_addr;
197
198 memset(&sock_addr, 0, sizeof(sock_addr));
199 icmp_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
200 sock_addr.sa_family = AF_INET;
201
202 /* first connect */
203 connect(icmp_sock, &sock_addr, sizeof(sock_addr));
204
205 /* disconnect */
206 sock_addr.sa_family = AF_UNSPEC;
207 connect(icmp_sock, &sock_addr, sizeof(sock_addr));
208
209 /* second disconnect -> crash */
210 sock_addr.sa_family = AF_UNSPEC;
211 connect(icmp_sock, &sock_addr, sizeof(sock_addr));
212
213 return true;
214 }
215
216 #define BUFS 256
217 #define IOV_LEN 16
218 #define OVERFLOW_BUF 7
219 #define FIXED_ADDR 0x45678000
220 #define TIMEOUT 60 /* seconds */
221
222 static struct iovec *iovs = NULL;
223 static int fd[2];
224 static void *overflow_addr;
225
func_map(void *)226 void* func_map(void*)
227 {
228 munmap(overflow_addr, PAGE_SIZE);
229 overflow_addr = mmap(overflow_addr, PAGE_SIZE, PROT_READ | PROT_WRITE,
230 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
231 return NULL;
232 }
233
func_readv(void *)234 void* func_readv(void*)
235 {
236 readv(fd[0], iovs, BUFS);
237 return NULL;
238 }
239
android_security_cts_NativeCodeTest_doPipeReadVTest(JNIEnv *,jobject)240 static jboolean android_security_cts_NativeCodeTest_doPipeReadVTest(JNIEnv*, jobject)
241 {
242 bool ret = false;
243 unsigned int i;
244 void *bufs[BUFS];
245 struct timespec ts;
246 time_t time;
247 pthread_t thr_map, thr_readv;
248
249 if (pipe(fd) < 0) {
250 ALOGE("pipe failed:%s", strerror(errno));
251 goto __out;
252 }
253 fcntl(fd[0], F_SETFL, O_NONBLOCK);
254 fcntl(fd[1], F_SETFL, O_NONBLOCK);
255
256 iovs = (struct iovec*)malloc(BUFS * sizeof(struct iovec));
257 if (iovs == NULL) {
258 ALOGE("malloc failed:%s", strerror(errno));
259 goto __close_pipe;
260 }
261
262 /*
263 * set up to overflow iov[OVERFLOW_BUF] on non-atomic redo in kernel
264 * function pipe_iov_copy_to_user
265 */
266 bufs[OVERFLOW_BUF] = mmap((void*)(FIXED_ADDR), PAGE_SIZE, PROT_READ | PROT_WRITE,
267 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
268 if (bufs[OVERFLOW_BUF] == MAP_FAILED) {
269 ALOGE("mmap fixed addr failed:%s", strerror(errno));
270 goto __close_pipe;
271 }
272 iovs[OVERFLOW_BUF].iov_base = bufs[OVERFLOW_BUF];
273 iovs[OVERFLOW_BUF].iov_len = IOV_LEN;
274
275 for (i = 0; i < BUFS; i++) {
276 if (i == OVERFLOW_BUF) {
277 continue;
278 }
279 bufs[i] = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
280 if(bufs[i] == MAP_FAILED) {
281 ALOGE("mmap failed in %d times:%s", i, strerror(errno));
282 goto __free_bufs;
283 }
284
285 iovs[i].iov_base = bufs[i];
286 iovs[i].iov_len = IOV_LEN;
287 }
288
289 clock_gettime(CLOCK_MONOTONIC, &ts);
290 time = ts.tv_sec;
291 while (1) {
292 write(fd[1], bufs[0], PAGE_SIZE);
293
294 pthread_create(&thr_map, NULL, func_map, NULL);
295 pthread_create(&thr_readv, NULL, func_readv, NULL);
296
297 pthread_join(thr_map, NULL);
298 pthread_join(thr_readv, NULL);
299
300 bufs[OVERFLOW_BUF] = overflow_addr;
301 if (bufs[OVERFLOW_BUF] == MAP_FAILED) {
302 ALOGE("mmap fixed addr failed:%s", strerror(errno));
303 goto __free_bufs;
304 }
305
306 clock_gettime(CLOCK_MONOTONIC, &ts);
307 if ((ts.tv_sec - time) > TIMEOUT) {
308 ret = true;
309 break;
310 }
311 }
312
313 __free_bufs:
314 for (i = 0; i < BUFS; i++) {
315 if (bufs[i]) {
316 munmap(bufs[i], PAGE_SIZE);
317 }
318 }
319
320 __free_iovs:
321 free(iovs);
322
323 __close_pipe:
324 close(fd[0]);
325 close(fd[1]);
326 __out:
327 return ret;
328 }
329
330 #define SHMEMSIZE 0x1 /* request one page */
android_security_cts_NativeCodeTest_doSysVipcTest(JNIEnv *,jobject)331 static jboolean android_security_cts_NativeCodeTest_doSysVipcTest(JNIEnv*, jobject)
332 {
333 key_t key = 0x1a25;
334
335 #if defined(__i386__) || (_MIPS_SIM == _MIPS_SIM_ABI32)
336 /* system call does not exist for x86 or mips 32 */
337 return true;
338 #else
339 /*
340 * Not supported in bionic. Must directly invoke syscall
341 * Only acceptable errno is ENOSYS: shmget syscall
342 * function not implemented
343 */
344 return ((syscall(SYS_shmget, key, SHMEMSIZE, IPC_CREAT | 0666) == -1)
345 && (errno == ENOSYS));
346 #endif
347 }
348
349 static JNINativeMethod gMethods[] = {
350 { "doPerfEventTest", "()Z",
351 (void *) android_security_cts_NativeCodeTest_doPerfEventTest },
352 { "doPerfEventTest2", "()Z",
353 (void *) android_security_cts_NativeCodeTest_doPerfEventTest2 },
354 { "doCVE20141710Test", "()Z",
355 (void *) android_security_cts_NativeCodeTest_doCVE20141710Test },
356 { "doFutexTest", "()Z",
357 (void *) android_security_cts_NativeCodeTest_doFutexTest },
358 { "doNvmapIocFromIdTest", "()Z",
359 (void *) android_security_cts_NativeCodeTest_doNvmapIocFromIdTest },
360 { "doPingPongRootTest", "()Z",
361 (void *) android_security_cts_NativeCodeTest_doPingPongRootTest },
362 { "doPipeReadVTest", "()Z",
363 (void *) android_security_cts_NativeCodeTest_doPipeReadVTest },
364 { "doSysVipcTest", "()Z",
365 (void *) android_security_cts_NativeCodeTest_doSysVipcTest },
366 };
367
register_android_security_cts_NativeCodeTest(JNIEnv * env)368 int register_android_security_cts_NativeCodeTest(JNIEnv* env)
369 {
370 jclass clazz = env->FindClass("android/security/cts/NativeCodeTest");
371 return env->RegisterNatives(clazz, gMethods,
372 sizeof(gMethods) / sizeof(JNINativeMethod));
373 }
374