Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2007 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 #define LOG_TAG "Zygote"
     18 
     19 #include <sys/types.h>
     20 #include <unistd.h>
     21 #include <fcntl.h>
     22 #include <utils/misc.h>
     23 #include <errno.h>
     24 #include <sys/select.h>
     25 
     26 #include "jni.h"
     27 #include <JNIHelp.h>
     28 #include "android_runtime/AndroidRuntime.h"
     29 
     30 #include <linux/capability.h>
     31 #include <linux/prctl.h>
     32 #include <sys/prctl.h>
     33 extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
     34 extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
     35 
     36 
     37 namespace android {
     38 
     39 /*
     40  * In class com.android.internal.os.ZygoteInit:
     41  * private static native boolean setreuid(int ruid, int euid)
     42  */
     43 static jint com_android_internal_os_ZygoteInit_setreuid(
     44     JNIEnv* env, jobject clazz, jint ruid, jint euid)
     45 {
     46     if (setreuid(ruid, euid) < 0) {
     47         return errno;
     48     }
     49     return 0;
     50 }
     51 
     52 /*
     53  * In class com.android.internal.os.ZygoteInit:
     54  * private static native int setregid(int rgid, int egid)
     55  */
     56 static jint com_android_internal_os_ZygoteInit_setregid(
     57     JNIEnv* env, jobject clazz, jint rgid, jint egid)
     58 {
     59     if (setregid(rgid, egid) < 0) {
     60         return errno;
     61     }
     62     return 0;
     63 }
     64 
     65 /*
     66  * In class com.android.internal.os.ZygoteInit:
     67  * private static native int setpgid(int rgid, int egid)
     68  */
     69 static jint com_android_internal_os_ZygoteInit_setpgid(
     70     JNIEnv* env, jobject clazz, jint pid, jint pgid)
     71 {
     72     if (setpgid(pid, pgid) < 0) {
     73         return errno;
     74     }
     75     return 0;
     76 }
     77 
     78 /*
     79  * In class com.android.internal.os.ZygoteInit:
     80  * private static native int getpgid(int pid)
     81  */
     82 static jint com_android_internal_os_ZygoteInit_getpgid(
     83     JNIEnv* env, jobject clazz, jint pid)
     84 {
     85     pid_t ret;
     86     ret = getpgid(pid);
     87 
     88     if (ret < 0) {
     89         jniThrowIOException(env, errno);
     90     }
     91 
     92     return ret;
     93 }
     94 
     95 static void com_android_internal_os_ZygoteInit_reopenStdio(JNIEnv* env,
     96         jobject clazz, jobject in, jobject out, jobject errfd)
     97 {
     98     int fd;
     99     int err;
    100 
    101     fd = jniGetFDFromFileDescriptor(env, in);
    102 
    103     if  (env->ExceptionOccurred() != NULL) {
    104         return;
    105     }
    106 
    107     do {
    108         err = dup2(fd, STDIN_FILENO);
    109     } while (err < 0 && errno == EINTR);
    110 
    111     fd = jniGetFDFromFileDescriptor(env, out);
    112 
    113     if  (env->ExceptionOccurred() != NULL) {
    114         return;
    115     }
    116 
    117     do {
    118         err = dup2(fd, STDOUT_FILENO);
    119     } while (err < 0 && errno == EINTR);
    120 
    121     fd = jniGetFDFromFileDescriptor(env, errfd);
    122 
    123     if  (env->ExceptionOccurred() != NULL) {
    124         return;
    125     }
    126 
    127     do {
    128         err = dup2(fd, STDERR_FILENO);
    129     } while (err < 0 && errno == EINTR);
    130 }
    131 
    132 static void com_android_internal_os_ZygoteInit_setCloseOnExec (JNIEnv *env,
    133     jobject clazz, jobject descriptor, jboolean flag)
    134 {
    135     int fd;
    136     int err;
    137     int fdFlags;
    138 
    139     fd = jniGetFDFromFileDescriptor(env, descriptor);
    140 
    141     if  (env->ExceptionOccurred() != NULL) {
    142         return;
    143     }
    144 
    145     fdFlags = fcntl(fd, F_GETFD);
    146 
    147     if (fdFlags < 0) {
    148         jniThrowIOException(env, errno);
    149         return;
    150     }
    151 
    152     if (flag) {
    153         fdFlags |= FD_CLOEXEC;
    154     } else {
    155         fdFlags &= ~FD_CLOEXEC;
    156     }
    157 
    158     err = fcntl(fd, F_SETFD, fdFlags);
    159 
    160     if (err < 0) {
    161         jniThrowIOException(env, errno);
    162         return;
    163     }
    164 }
    165 
    166 static void com_android_internal_os_ZygoteInit_setCapabilities (JNIEnv *env,
    167     jobject clazz, jlong permitted, jlong effective)
    168 {
    169     struct __user_cap_header_struct capheader;
    170     struct __user_cap_data_struct capdata;
    171     int err;
    172 
    173     memset (&capheader, 0, sizeof(capheader));
    174     memset (&capdata, 0, sizeof(capdata));
    175 
    176     capheader.version = _LINUX_CAPABILITY_VERSION;
    177     capheader.pid = 0;
    178 
    179     // As of this writing, capdata is __u32, but that's expected
    180     // to change...
    181     capdata.effective = effective;
    182     capdata.permitted = permitted;
    183 
    184     err = capset (&capheader, &capdata);
    185 
    186     if (err < 0) {
    187         jniThrowIOException(env, errno);
    188         return;
    189     }
    190 }
    191 
    192 static jlong com_android_internal_os_ZygoteInit_capgetPermitted (JNIEnv *env,
    193     jobject clazz, jint pid)
    194 {
    195     struct __user_cap_header_struct capheader;
    196     struct __user_cap_data_struct capdata;
    197     int err;
    198 
    199     memset (&capheader, 0, sizeof(capheader));
    200     memset (&capdata, 0, sizeof(capdata));
    201 
    202     capheader.version = _LINUX_CAPABILITY_VERSION;
    203     capheader.pid = pid;
    204 
    205     err = capget (&capheader, &capdata);
    206 
    207     if (err < 0) {
    208         jniThrowIOException(env, errno);
    209         return 0;
    210     }
    211 
    212     return (jlong) capdata.permitted;
    213 }
    214 
    215 static jint com_android_internal_os_ZygoteInit_selectReadable (
    216         JNIEnv *env, jobject clazz, jobjectArray fds)
    217 {
    218     if (fds == NULL) {
    219         jniThrowNullPointerException(env, "fds == null");
    220         return -1;
    221     }
    222 
    223     jsize length = env->GetArrayLength(fds);
    224     fd_set fdset;
    225 
    226     if (env->ExceptionOccurred() != NULL) {
    227         return -1;
    228     }
    229 
    230     FD_ZERO(&fdset);
    231 
    232     int nfds = 0;
    233     for (jsize i = 0; i < length; i++) {
    234         jobject fdObj = env->GetObjectArrayElement(fds, i);
    235         if  (env->ExceptionOccurred() != NULL) {
    236             return -1;
    237         }
    238         if (fdObj == NULL) {
    239             continue;
    240         }
    241         int fd = jniGetFDFromFileDescriptor(env, fdObj);
    242         if  (env->ExceptionOccurred() != NULL) {
    243             return -1;
    244         }
    245 
    246         FD_SET(fd, &fdset);
    247 
    248         if (fd >= nfds) {
    249             nfds = fd + 1;
    250         }
    251     }
    252 
    253     int err;
    254     do {
    255         err = select (nfds, &fdset, NULL, NULL, NULL);
    256     } while (err < 0 && errno == EINTR);
    257 
    258     if (err < 0) {
    259         jniThrowIOException(env, errno);
    260         return -1;
    261     }
    262 
    263     for (jsize i = 0; i < length; i++) {
    264         jobject fdObj = env->GetObjectArrayElement(fds, i);
    265         if  (env->ExceptionOccurred() != NULL) {
    266             return -1;
    267         }
    268         if (fdObj == NULL) {
    269             continue;
    270         }
    271         int fd = jniGetFDFromFileDescriptor(env, fdObj);
    272         if  (env->ExceptionOccurred() != NULL) {
    273             return -1;
    274         }
    275         if (FD_ISSET(fd, &fdset)) {
    276             return (jint)i;
    277         }
    278     }
    279     return -1;
    280 }
    281 
    282 static jobject com_android_internal_os_ZygoteInit_createFileDescriptor (
    283         JNIEnv *env, jobject clazz, jint fd)
    284 {
    285     return jniCreateFileDescriptor(env, fd);
    286 }
    287 
    288 /*
    289  * JNI registration.
    290  */
    291 static JNINativeMethod gMethods[] = {
    292     /* name, signature, funcPtr */
    293     { "setreuid", "(II)I",
    294       (void*) com_android_internal_os_ZygoteInit_setreuid },
    295     { "setregid", "(II)I",
    296       (void*) com_android_internal_os_ZygoteInit_setregid },
    297     { "setpgid", "(II)I",
    298       (void *) com_android_internal_os_ZygoteInit_setpgid },
    299     { "getpgid", "(I)I",
    300       (void *) com_android_internal_os_ZygoteInit_getpgid },
    301     { "reopenStdio",
    302         "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;"
    303         "Ljava/io/FileDescriptor;)V",
    304             (void *) com_android_internal_os_ZygoteInit_reopenStdio},
    305     { "setCloseOnExec", "(Ljava/io/FileDescriptor;Z)V",
    306         (void *)  com_android_internal_os_ZygoteInit_setCloseOnExec},
    307     { "setCapabilities", "(JJ)V",
    308         (void *) com_android_internal_os_ZygoteInit_setCapabilities },
    309     { "capgetPermitted", "(I)J",
    310         (void *) com_android_internal_os_ZygoteInit_capgetPermitted },
    311     { "selectReadable", "([Ljava/io/FileDescriptor;)I",
    312         (void *) com_android_internal_os_ZygoteInit_selectReadable },
    313     { "createFileDescriptor", "(I)Ljava/io/FileDescriptor;",
    314         (void *) com_android_internal_os_ZygoteInit_createFileDescriptor }
    315 };
    316 int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
    317 {
    318     return AndroidRuntime::registerNativeMethods(env,
    319             "com/android/internal/os/ZygoteInit", gMethods, NELEM(gMethods));
    320 }
    321 
    322 }; // namespace android
    323