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 <linux/sysctl.h> 37 #include <arpa/inet.h> 38 #include <linux/ipc.h> 39 #include <pthread.h> 40 41 /* 42 * Returns true iff this device is vulnerable to CVE-2013-2094. 43 * A patch for CVE-2013-2094 can be found at 44 * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=8176cced706b5e5d15887584150764894e94e02f 45 */ 46 static jboolean android_security_cts_NativeCodeTest_doPerfEventTest(JNIEnv* env, jobject thiz) 47 { 48 uint64_t attr[10] = { 0x4800000001, (uint32_t) -1, 0, 0, 0, 0x300 }; 49 50 int fd = syscall(__NR_perf_event_open, attr, 0, -1, -1, 0); 51 jboolean result = (fd != -1); 52 53 if (fd != -1) { 54 close(fd); 55 } 56 57 return result; 58 } 59 60 /* 61 * Detects if the following patch is present. 62 * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c95eb3184ea1a3a2551df57190c81da695e2144b 63 * 64 * Returns true if the patch is applied, or crashes the system otherwise. 65 * 66 * While you're at it, you want to apply the following patch too. 67 * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=b88a2595b6d8aedbd275c07dfa784657b4f757eb 68 * This test doesn't cover the above patch. TODO write a new test. 69 * 70 * Credit: https://github.com/deater/perf_event_tests/blob/master/exploits/arm_perf_exploit.c 71 */ 72 static jboolean android_security_cts_NativeCodeTest_doPerfEventTest2(JNIEnv* env, jobject thiz) 73 { 74 struct perf_event_attr pe[2]; 75 int fd[2]; 76 memset(pe, 0, sizeof(pe)); 77 pe[0].type = 2; 78 pe[0].config = 72; 79 pe[0].size = 80; 80 pe[1].type = PERF_TYPE_RAW; 81 pe[1].size = 80; 82 fd[0]=syscall(__NR_perf_event_open, &pe[0], 0, 0, -1, 0); 83 fd[1]=syscall(__NR_perf_event_open, &pe[1], 0, 0, fd[0], 0); 84 close(fd[0]); 85 close(fd[1]); 86 return true; 87 } 88 89 /* 90 * Prior to https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/arch/arm/include/asm/uaccess.h?id=8404663f81d212918ff85f493649a7991209fa04 91 * there was a flaw in the kernel's handling of get_user and put_user 92 * requests. Normally, get_user and put_user are supposed to guarantee 93 * that reads/writes outside the process's address space are not 94 * allowed. 95 * 96 * In this test, we use sysctl to force a read from an address outside 97 * of our address space (but in the kernel's address space). Without the 98 * patch applied, this read succeeds, because sysctl uses the 99 * vulnerable get_user call. 100 * 101 * This function returns true if the patch above is applied, or false 102 * otherwise. 103 * 104 * Credit: https://twitter.com/grsecurity/status/401443359912239105 105 */ 106 static jboolean android_security_cts_NativeCodeTest_doVrootTest(JNIEnv*, jobject) 107 { 108 #ifdef __arm__ 109 ALOGE("Starting doVrootTest"); 110 111 struct __sysctl_args args; 112 char osname[100]; 113 int name[] = { CTL_KERN, KERN_OSTYPE }; 114 115 memset(&args, 0, sizeof(struct __sysctl_args)); 116 args.name = name; 117 args.nlen = sizeof(name)/sizeof(name[0]); 118 args.oldval = osname; 119 args.oldlenp = (size_t *) 0xc0000000; // PAGE_OFFSET 120 121 int result = syscall(__NR__sysctl, &args); 122 return ((result == -1) && (errno == EFAULT || errno == ENOSYS)); 123 #else 124 return true; 125 #endif 126 } 127 128 static void* mmap_syscall(void* addr, size_t len, int prot, int flags, int fd, off_t offset) 129 { 130 #ifdef __LP64__ 131 return mmap(addr, len, prot, flags, fd, offset); 132 #else 133 return (void*) syscall(__NR_mmap2, addr, len, prot, flags, fd, offset); 134 #endif 135 } 136 137 #define KBASE_REG_COOKIE_TB 2 138 #define KBASE_REG_COOKIE_MTP 3 139 140 /* 141 * Returns true if the device is immune to CVE-2014-1710, 142 * false if the device is vulnerable. 143 */ 144 static jboolean android_security_cts_NativeCodeTest_doCVE20141710Test(JNIEnv*, jobject) 145 { 146 jboolean result = false; 147 int fd = open("/dev/mali0", O_RDWR); 148 if (fd < 0) { 149 return true; /* not vulnerable */ 150 } 151 152 void* a = mmap_syscall(NULL, 0x1000, PROT_READ, MAP_SHARED, fd, KBASE_REG_COOKIE_MTP); 153 void* b = mmap_syscall(NULL, 0x1000, PROT_READ, MAP_SHARED, fd, KBASE_REG_COOKIE_TB); 154 155 if (a == MAP_FAILED) { 156 result = true; /* assume not vulnerable */ 157 goto done; 158 } 159 160 if (b == MAP_FAILED) { 161 result = true; /* assume not vulnerable */ 162 goto done; 163 } 164 165 /* mprotect should return an error if not vulnerable */ 166 result = (mprotect(b, 0x1000, PROT_READ | PROT_WRITE) == -1); 167 168 done: 169 if (a != MAP_FAILED) { 170 munmap(a, 0x1000); 171 } 172 if (b != MAP_FAILED) { 173 munmap(b, 0x1000); 174 } 175 close(fd); 176 return result; 177 } 178 179 static inline int futex_syscall(volatile int* uaddr, int op, int val, const struct timespec* ts, 180 volatile int* uaddr2, int val3) { 181 return syscall(__NR_futex, uaddr, op, val, ts, uaddr2, val3); 182 } 183 184 /* 185 * Test for vulnerability to CVE-2014-3153, a bug in the futex() syscall that can 186 * lead to privilege escalation and was used by the towelroot exploit. Returns true 187 * if device is patched, false if still vulnerable. 188 */ 189 static jboolean android_security_cts_NativeCodeTest_doFutexTest(JNIEnv*, jobject) 190 { 191 jboolean result = false; 192 193 int futex = 1; 194 int ret; 195 196 /* The patch will reject FUTEX_CMP_REQUEUE_PI calls where addr == addr2, so 197 * that's what we're checking for - they're both &futex. Patched systems will 198 * return -1 and set errno to 22 (EINVAL), vulnerable systems will return 0. 199 */ 200 ret = futex_syscall(&futex, FUTEX_CMP_REQUEUE_PI, 1, NULL, &futex, 0); 201 return (ret == -1 && errno == EINVAL); 202 } 203 204 static jboolean android_security_cts_NativeCodeTest_doNvmapIocFromIdTest(JNIEnv*, jobject) 205 { 206 /* 207 * IOCTL code specified from the original notification. 208 * Also available in: 209 * .../kernel/tegra/drivers/video/tegra/nvmap/nvmap_ioctl.h 210 * #define NVMAP_IOC_MAGIC 'N' 211 * #define NVMAP_IOC_FROM_ID _IOWR(NVMAP_IOC_MAGIC, 2, struct nvmap_create_handle) 212 */ 213 const int NVMAP_IOC_FROM_ID = 0xc0084e02; 214 int nvmap = open("/dev/nvmap", O_RDWR | O_CLOEXEC, 0); 215 bool vulnerable = false; 216 217 if (nvmap >= 0) { 218 if (0 == ioctl(nvmap, NVMAP_IOC_FROM_ID)) { 219 /* IOCTL succeeded */ 220 vulnerable = true; 221 } 222 else if (errno != ENOTTY) { 223 /* IOCTL failed, but provided the wrong error number */ 224 vulnerable = true; 225 } 226 227 close(nvmap); 228 } 229 230 return !vulnerable; 231 } 232 233 static jboolean android_security_cts_NativeCodeTest_doPingPongRootTest(JNIEnv*, jobject) 234 { 235 int icmp_sock; 236 struct sockaddr sock_addr; 237 238 memset(&sock_addr, 0, sizeof(sock_addr)); 239 icmp_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); 240 sock_addr.sa_family = AF_INET; 241 242 /* first connect */ 243 connect(icmp_sock, &sock_addr, sizeof(sock_addr)); 244 245 /* disconnect */ 246 sock_addr.sa_family = AF_UNSPEC; 247 connect(icmp_sock, &sock_addr, sizeof(sock_addr)); 248 249 /* second disconnect -> crash */ 250 sock_addr.sa_family = AF_UNSPEC; 251 connect(icmp_sock, &sock_addr, sizeof(sock_addr)); 252 253 return true; 254 } 255 256 #define BUFS 256 257 #define IOV_LEN 16 258 #define OVERFLOW_BUF 7 259 #define FIXED_ADDR 0x45678000 260 #define TIMEOUT 60 /* seconds */ 261 262 static struct iovec *iovs = NULL; 263 static int fd[2]; 264 static void *overflow_addr; 265 266 void* func_map(void*) 267 { 268 munmap(overflow_addr, PAGE_SIZE); 269 overflow_addr = mmap(overflow_addr, PAGE_SIZE, PROT_READ | PROT_WRITE, 270 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 271 return NULL; 272 } 273 274 void* func_readv(void*) 275 { 276 readv(fd[0], iovs, BUFS); 277 return NULL; 278 } 279 280 static jboolean android_security_cts_NativeCodeTest_doPipeReadVTest(JNIEnv*, jobject) 281 { 282 bool ret = false; 283 unsigned int i; 284 void *bufs[BUFS]; 285 struct timespec ts; 286 time_t time; 287 pthread_t thr_map, thr_readv; 288 289 if (pipe(fd) < 0) { 290 ALOGE("pipe failed:%s", strerror(errno)); 291 goto __out; 292 } 293 fcntl(fd[0], F_SETFL, O_NONBLOCK); 294 fcntl(fd[1], F_SETFL, O_NONBLOCK); 295 296 iovs = (struct iovec*)malloc(BUFS * sizeof(struct iovec)); 297 if (iovs == NULL) { 298 ALOGE("malloc failed:%s", strerror(errno)); 299 goto __close_pipe; 300 } 301 302 /* 303 * set up to overflow iov[OVERFLOW_BUF] on non-atomic redo in kernel 304 * function pipe_iov_copy_to_user 305 */ 306 iovs[OVERFLOW_BUF - 1].iov_len = IOV_LEN*10; 307 iovs[OVERFLOW_BUF].iov_base = bufs[OVERFLOW_BUF]; 308 iovs[OVERFLOW_BUF].iov_len = IOV_LEN; 309 310 overflow_addr = mmap((void *) FIXED_ADDR, PAGE_SIZE, PROT_READ | PROT_WRITE, 311 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 312 313 bufs[OVERFLOW_BUF] = overflow_addr; 314 if (bufs[OVERFLOW_BUF] == MAP_FAILED) { 315 ALOGE("mmap fixed addr failed:%s", strerror(errno)); 316 goto __close_pipe; 317 } 318 319 for (i = 0; i < BUFS; i++) { 320 if (i == OVERFLOW_BUF) { 321 continue; 322 } 323 bufs[i] = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); 324 if(bufs[i] == MAP_FAILED) { 325 ALOGE("mmap failed in %d times:%s", i, strerror(errno)); 326 goto __free_bufs; 327 } 328 329 iovs[i].iov_base = bufs[i]; 330 iovs[i].iov_len = IOV_LEN; 331 } 332 333 clock_gettime(CLOCK_MONOTONIC, &ts); 334 time = ts.tv_sec; 335 while (1) { 336 write(fd[1], bufs[0], PAGE_SIZE); 337 338 pthread_create(&thr_map, NULL, func_map, NULL); 339 pthread_create(&thr_readv, NULL, func_readv, NULL); 340 341 pthread_join(thr_map, NULL); 342 pthread_join(thr_readv, NULL); 343 344 bufs[OVERFLOW_BUF] = overflow_addr; 345 if (bufs[OVERFLOW_BUF] == MAP_FAILED) { 346 ALOGE("mmap fixed addr failed:%s", strerror(errno)); 347 goto __free_bufs; 348 } 349 350 clock_gettime(CLOCK_MONOTONIC, &ts); 351 if ((ts.tv_sec - time) > TIMEOUT) { 352 ret = true; 353 break; 354 } 355 } 356 357 __free_bufs: 358 for (i = 0; i < BUFS; i++) { 359 if (bufs[i]) { 360 munmap(bufs[i], PAGE_SIZE); 361 } 362 } 363 364 __free_iovs: 365 free(iovs); 366 367 __close_pipe: 368 close(fd[0]); 369 close(fd[1]); 370 __out: 371 return ret; 372 } 373 374 #define SHMEMSIZE 0x1 /* request one page */ 375 static jboolean android_security_cts_NativeCodeTest_doSysVipcTest(JNIEnv*, jobject) 376 { 377 key_t key = 0x1a25; 378 379 #if defined(__i386__) || (_MIPS_SIM == _MIPS_SIM_ABI32) 380 /* system call does not exist for x86 or mips 32 */ 381 return true; 382 #else 383 /* 384 * Not supported in bionic. Must directly invoke syscall 385 * Only acceptable errno is ENOSYS: shmget syscall 386 * function not implemented 387 */ 388 return ((syscall(SYS_shmget, key, SHMEMSIZE, IPC_CREAT | 0666) == -1) 389 && (errno == ENOSYS)); 390 #endif 391 } 392 393 static JNINativeMethod gMethods[] = { 394 { "doPerfEventTest", "()Z", 395 (void *) android_security_cts_NativeCodeTest_doPerfEventTest }, 396 { "doPerfEventTest2", "()Z", 397 (void *) android_security_cts_NativeCodeTest_doPerfEventTest2 }, 398 { "doVrootTest", "()Z", 399 (void *) android_security_cts_NativeCodeTest_doVrootTest }, 400 { "doCVE20141710Test", "()Z", 401 (void *) android_security_cts_NativeCodeTest_doCVE20141710Test }, 402 { "doFutexTest", "()Z", 403 (void *) android_security_cts_NativeCodeTest_doFutexTest }, 404 { "doNvmapIocFromIdTest", "()Z", 405 (void *) android_security_cts_NativeCodeTest_doNvmapIocFromIdTest }, 406 { "doPingPongRootTest", "()Z", 407 (void *) android_security_cts_NativeCodeTest_doPingPongRootTest }, 408 { "doPipeReadVTest", "()Z", 409 (void *) android_security_cts_NativeCodeTest_doPipeReadVTest }, 410 { "doSysVipcTest", "()Z", 411 (void *) android_security_cts_NativeCodeTest_doSysVipcTest }, 412 }; 413 414 int register_android_security_cts_NativeCodeTest(JNIEnv* env) 415 { 416 jclass clazz = env->FindClass("android/security/cts/NativeCodeTest"); 417 return env->RegisterNatives(clazz, gMethods, 418 sizeof(gMethods) / sizeof(JNINativeMethod)); 419 } 420