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 <sys/capability.h> 31#include <sys/prctl.h> 32 33namespace android { 34 35/* 36 * In class com.android.internal.os.ZygoteInit: 37 * private static native boolean setreuid(int ruid, int euid) 38 */ 39static jint com_android_internal_os_ZygoteInit_setreuid( 40 JNIEnv* env, jobject clazz, jint ruid, jint euid) 41{ 42 if (setreuid(ruid, euid) < 0) { 43 return errno; 44 } 45 return 0; 46} 47 48/* 49 * In class com.android.internal.os.ZygoteInit: 50 * private static native int setregid(int rgid, int egid) 51 */ 52static jint com_android_internal_os_ZygoteInit_setregid( 53 JNIEnv* env, jobject clazz, jint rgid, jint egid) 54{ 55 if (setregid(rgid, egid) < 0) { 56 return errno; 57 } 58 return 0; 59} 60 61/* 62 * In class com.android.internal.os.ZygoteInit: 63 * private static native int setpgid(int rgid, int egid) 64 */ 65static jint com_android_internal_os_ZygoteInit_setpgid( 66 JNIEnv* env, jobject clazz, jint pid, jint pgid) 67{ 68 if (setpgid(pid, pgid) < 0) { 69 return errno; 70 } 71 return 0; 72} 73 74/* 75 * In class com.android.internal.os.ZygoteInit: 76 * private static native int getpgid(int pid) 77 */ 78static jint com_android_internal_os_ZygoteInit_getpgid( 79 JNIEnv* env, jobject clazz, jint pid) 80{ 81 pid_t ret; 82 ret = getpgid(pid); 83 84 if (ret < 0) { 85 jniThrowIOException(env, errno); 86 } 87 88 return ret; 89} 90 91static void com_android_internal_os_ZygoteInit_reopenStdio(JNIEnv* env, 92 jobject clazz, jobject in, jobject out, jobject errfd) 93{ 94 int fd; 95 int err; 96 97 fd = jniGetFDFromFileDescriptor(env, in); 98 99 if (env->ExceptionOccurred() != NULL) { 100 return; 101 } 102 103 do { 104 err = dup2(fd, STDIN_FILENO); 105 } while (err < 0 && errno == EINTR); 106 107 fd = jniGetFDFromFileDescriptor(env, out); 108 109 if (env->ExceptionOccurred() != NULL) { 110 return; 111 } 112 113 do { 114 err = dup2(fd, STDOUT_FILENO); 115 } while (err < 0 && errno == EINTR); 116 117 fd = jniGetFDFromFileDescriptor(env, errfd); 118 119 if (env->ExceptionOccurred() != NULL) { 120 return; 121 } 122 123 do { 124 err = dup2(fd, STDERR_FILENO); 125 } while (err < 0 && errno == EINTR); 126} 127 128static void com_android_internal_os_ZygoteInit_setCloseOnExec (JNIEnv *env, 129 jobject clazz, jobject descriptor, jboolean flag) 130{ 131 int fd; 132 int err; 133 int fdFlags; 134 135 fd = jniGetFDFromFileDescriptor(env, descriptor); 136 137 if (env->ExceptionOccurred() != NULL) { 138 return; 139 } 140 141 fdFlags = fcntl(fd, F_GETFD); 142 143 if (fdFlags < 0) { 144 jniThrowIOException(env, errno); 145 return; 146 } 147 148 if (flag) { 149 fdFlags |= FD_CLOEXEC; 150 } else { 151 fdFlags &= ~FD_CLOEXEC; 152 } 153 154 err = fcntl(fd, F_SETFD, fdFlags); 155 156 if (err < 0) { 157 jniThrowIOException(env, errno); 158 return; 159 } 160} 161 162static jlong com_android_internal_os_ZygoteInit_capgetPermitted (JNIEnv *env, 163 jobject clazz, jint pid) 164{ 165 struct __user_cap_header_struct capheader; 166 struct __user_cap_data_struct capdata; 167 int err; 168 169 memset (&capheader, 0, sizeof(capheader)); 170 memset (&capdata, 0, sizeof(capdata)); 171 172 capheader.version = _LINUX_CAPABILITY_VERSION; 173 capheader.pid = pid; 174 175 err = capget (&capheader, &capdata); 176 177 if (err < 0) { 178 jniThrowIOException(env, errno); 179 return 0; 180 } 181 182 return (jlong) capdata.permitted; 183} 184 185static jint com_android_internal_os_ZygoteInit_selectReadable ( 186 JNIEnv *env, jobject clazz, jobjectArray fds) 187{ 188 if (fds == NULL) { 189 jniThrowNullPointerException(env, "fds == null"); 190 return -1; 191 } 192 193 jsize length = env->GetArrayLength(fds); 194 fd_set fdset; 195 196 if (env->ExceptionOccurred() != NULL) { 197 return -1; 198 } 199 200 FD_ZERO(&fdset); 201 202 int nfds = 0; 203 for (jsize i = 0; i < length; i++) { 204 jobject fdObj = env->GetObjectArrayElement(fds, i); 205 if (env->ExceptionOccurred() != NULL) { 206 return -1; 207 } 208 if (fdObj == NULL) { 209 continue; 210 } 211 int fd = jniGetFDFromFileDescriptor(env, fdObj); 212 if (env->ExceptionOccurred() != NULL) { 213 return -1; 214 } 215 216 FD_SET(fd, &fdset); 217 218 if (fd >= nfds) { 219 nfds = fd + 1; 220 } 221 } 222 223 int err; 224 do { 225 err = select (nfds, &fdset, NULL, NULL, NULL); 226 } while (err < 0 && errno == EINTR); 227 228 if (err < 0) { 229 jniThrowIOException(env, errno); 230 return -1; 231 } 232 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 if (FD_ISSET(fd, &fdset)) { 246 return (jint)i; 247 } 248 } 249 return -1; 250} 251 252static jobject com_android_internal_os_ZygoteInit_createFileDescriptor ( 253 JNIEnv *env, jobject clazz, jint fd) 254{ 255 return jniCreateFileDescriptor(env, fd); 256} 257 258/* 259 * JNI registration. 260 */ 261static JNINativeMethod gMethods[] = { 262 /* name, signature, funcPtr */ 263 { "setreuid", "(II)I", 264 (void*) com_android_internal_os_ZygoteInit_setreuid }, 265 { "setregid", "(II)I", 266 (void*) com_android_internal_os_ZygoteInit_setregid }, 267 { "setpgid", "(II)I", 268 (void *) com_android_internal_os_ZygoteInit_setpgid }, 269 { "getpgid", "(I)I", 270 (void *) com_android_internal_os_ZygoteInit_getpgid }, 271 { "reopenStdio", 272 "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;" 273 "Ljava/io/FileDescriptor;)V", 274 (void *) com_android_internal_os_ZygoteInit_reopenStdio}, 275 { "setCloseOnExec", "(Ljava/io/FileDescriptor;Z)V", 276 (void *) com_android_internal_os_ZygoteInit_setCloseOnExec}, 277 { "capgetPermitted", "(I)J", 278 (void *) com_android_internal_os_ZygoteInit_capgetPermitted }, 279 { "selectReadable", "([Ljava/io/FileDescriptor;)I", 280 (void *) com_android_internal_os_ZygoteInit_selectReadable }, 281 { "createFileDescriptor", "(I)Ljava/io/FileDescriptor;", 282 (void *) com_android_internal_os_ZygoteInit_createFileDescriptor } 283}; 284int register_com_android_internal_os_ZygoteInit(JNIEnv* env) 285{ 286 return AndroidRuntime::registerNativeMethods(env, 287 "com/android/internal/os/ZygoteInit", gMethods, NELEM(gMethods)); 288} 289 290}; // namespace android 291