Home | History | Annotate | Download | only in jni
      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