• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
android_security_cts_NativeCodeTest_doPerfEventTest(JNIEnv * env,jobject thiz)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  */
android_security_cts_NativeCodeTest_doPerfEventTest2(JNIEnv * env,jobject thiz)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  */
android_security_cts_NativeCodeTest_doVrootTest(JNIEnv *,jobject)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 
mmap_syscall(void * addr,size_t len,int prot,int flags,int fd,off_t offset)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  */
android_security_cts_NativeCodeTest_doCVE20141710Test(JNIEnv *,jobject)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 
futex_syscall(volatile int * uaddr,int op,int val,const struct timespec * ts,volatile int * uaddr2,int val3)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  */
android_security_cts_NativeCodeTest_doFutexTest(JNIEnv *,jobject)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 
android_security_cts_NativeCodeTest_doNvmapIocFromIdTest(JNIEnv *,jobject)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 
android_security_cts_NativeCodeTest_doPingPongRootTest(JNIEnv *,jobject)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 
func_map(void *)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 
func_readv(void *)274 void* func_readv(void*)
275 {
276     readv(fd[0], iovs, BUFS);
277     return NULL;
278 }
279 
android_security_cts_NativeCodeTest_doPipeReadVTest(JNIEnv *,jobject)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 */
android_security_cts_NativeCodeTest_doSysVipcTest(JNIEnv *,jobject)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 
register_android_security_cts_NativeCodeTest(JNIEnv * env)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