blob: e627e4a2b9535a5a4f9b11bc7d21308b5da32d88 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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#ifdef HAVE_ANDROID_OS
31#include <linux/capability.h>
32#include <linux/prctl.h>
33#include <sys/prctl.h>
34extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
35extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
36#endif
37
38
39namespace android {
40
41/*
42 * In class com.android.internal.os.ZygoteInit:
43 * private static native boolean setreuid(int ruid, int euid)
44 */
45static jint com_android_internal_os_ZygoteInit_setreuid(
46 JNIEnv* env, jobject clazz, jint ruid, jint euid)
47{
Andy McFadden05554a42011-01-10 11:22:43 -080048 if (setreuid(ruid, euid) < 0) {
49 return errno;
50 }
51 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052}
53
54/*
55 * In class com.android.internal.os.ZygoteInit:
56 * private static native int setregid(int rgid, int egid)
57 */
58static jint com_android_internal_os_ZygoteInit_setregid(
59 JNIEnv* env, jobject clazz, jint rgid, jint egid)
60{
Andy McFadden05554a42011-01-10 11:22:43 -080061 if (setregid(rgid, egid) < 0) {
62 return errno;
63 }
64 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065}
66
67/*
68 * In class com.android.internal.os.ZygoteInit:
69 * private static native int setpgid(int rgid, int egid)
70 */
71static jint com_android_internal_os_ZygoteInit_setpgid(
72 JNIEnv* env, jobject clazz, jint pid, jint pgid)
73{
Andy McFadden05554a42011-01-10 11:22:43 -080074 if (setpgid(pid, pgid) < 0) {
75 return errno;
76 }
77 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078}
79
80/*
81 * In class com.android.internal.os.ZygoteInit:
82 * private static native int getpgid(int pid)
83 */
84static jint com_android_internal_os_ZygoteInit_getpgid(
85 JNIEnv* env, jobject clazz, jint pid)
86{
87 pid_t ret;
88 ret = getpgid(pid);
89
90 if (ret < 0) {
91 jniThrowIOException(env, errno);
92 }
93
94 return ret;
95}
96
Elliott Hughes69a017b2011-04-08 14:10:28 -070097static void com_android_internal_os_ZygoteInit_reopenStdio(JNIEnv* env,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 jobject clazz, jobject in, jobject out, jobject errfd)
99{
100 int fd;
101 int err;
102
103 fd = jniGetFDFromFileDescriptor(env, in);
104
105 if (env->ExceptionOccurred() != NULL) {
106 return;
107 }
108
109 do {
110 err = dup2(fd, STDIN_FILENO);
111 } while (err < 0 && errno == EINTR);
112
113 fd = jniGetFDFromFileDescriptor(env, out);
114
115 if (env->ExceptionOccurred() != NULL) {
116 return;
117 }
118
119 do {
120 err = dup2(fd, STDOUT_FILENO);
121 } while (err < 0 && errno == EINTR);
122
123 fd = jniGetFDFromFileDescriptor(env, errfd);
124
125 if (env->ExceptionOccurred() != NULL) {
126 return;
127 }
128
129 do {
130 err = dup2(fd, STDERR_FILENO);
131 } while (err < 0 && errno == EINTR);
132}
133
Elliott Hughes69a017b2011-04-08 14:10:28 -0700134static void com_android_internal_os_ZygoteInit_closeDescriptor(JNIEnv* env,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 jobject clazz, jobject descriptor)
136{
137 int fd;
138 int err;
139
140 fd = jniGetFDFromFileDescriptor(env, descriptor);
141
142 if (env->ExceptionOccurred() != NULL) {
143 return;
144 }
145
146 do {
147 err = close(fd);
148 } while (err < 0 && errno == EINTR);
149
150 if (err < 0) {
151 jniThrowIOException(env, errno);
152 return;
153 }
154}
155
156static void com_android_internal_os_ZygoteInit_setCloseOnExec (JNIEnv *env,
157 jobject clazz, jobject descriptor, jboolean flag)
158{
159 int fd;
160 int err;
161 int fdFlags;
162
163 fd = jniGetFDFromFileDescriptor(env, descriptor);
164
165 if (env->ExceptionOccurred() != NULL) {
166 return;
167 }
168
169 fdFlags = fcntl(fd, F_GETFD);
170
171 if (fdFlags < 0) {
172 jniThrowIOException(env, errno);
173 return;
174 }
175
176 if (flag) {
177 fdFlags |= FD_CLOEXEC;
178 } else {
179 fdFlags &= ~FD_CLOEXEC;
180 }
181
182 err = fcntl(fd, F_SETFD, fdFlags);
183
184 if (err < 0) {
185 jniThrowIOException(env, errno);
186 return;
187 }
188}
189
190static void com_android_internal_os_ZygoteInit_setCapabilities (JNIEnv *env,
191 jobject clazz, jlong permitted, jlong effective)
192{
193#ifdef HAVE_ANDROID_OS
194 struct __user_cap_header_struct capheader;
195 struct __user_cap_data_struct capdata;
196 int err;
197
198 memset (&capheader, 0, sizeof(capheader));
199 memset (&capdata, 0, sizeof(capdata));
200
201 capheader.version = _LINUX_CAPABILITY_VERSION;
202 capheader.pid = 0;
203
204 // As of this writing, capdata is __u32, but that's expected
205 // to change...
206 capdata.effective = effective;
207 capdata.permitted = permitted;
208
Elliott Hughes69a017b2011-04-08 14:10:28 -0700209 err = capset (&capheader, &capdata);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210
211 if (err < 0) {
212 jniThrowIOException(env, errno);
213 return;
214 }
215#endif /* HAVE_ANDROID_OS */
216}
217
218static jlong com_android_internal_os_ZygoteInit_capgetPermitted (JNIEnv *env,
219 jobject clazz, jint pid)
220{
221#ifndef HAVE_ANDROID_OS
222 return (jlong)0;
223#else
224 struct __user_cap_header_struct capheader;
225 struct __user_cap_data_struct capdata;
226 int err;
227
228 memset (&capheader, 0, sizeof(capheader));
229 memset (&capdata, 0, sizeof(capdata));
230
231 capheader.version = _LINUX_CAPABILITY_VERSION;
232 capheader.pid = pid;
233
Elliott Hughes69a017b2011-04-08 14:10:28 -0700234 err = capget (&capheader, &capdata);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235
236 if (err < 0) {
237 jniThrowIOException(env, errno);
238 return 0;
239 }
240
241 return (jlong) capdata.permitted;
242#endif /* HAVE_ANDROID_OS */
243}
244
245static jint com_android_internal_os_ZygoteInit_selectReadable (
Elliott Hughes69a017b2011-04-08 14:10:28 -0700246 JNIEnv *env, jobject clazz, jobjectArray fds)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247{
248 if (fds == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700249 jniThrowNullPointerException(env, "fds == null");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 return -1;
251 }
252
253 jsize length = env->GetArrayLength(fds);
254 fd_set fdset;
255
256 if (env->ExceptionOccurred() != NULL) {
257 return -1;
258 }
259
260 FD_ZERO(&fdset);
261
262 int nfds = 0;
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
276 FD_SET(fd, &fdset);
277
278 if (fd >= nfds) {
279 nfds = fd + 1;
280 }
281 }
282
283 int err;
284 do {
285 err = select (nfds, &fdset, NULL, NULL, NULL);
286 } while (err < 0 && errno == EINTR);
287
288 if (err < 0) {
289 jniThrowIOException(env, errno);
290 return -1;
291 }
292
293 for (jsize i = 0; i < length; i++) {
294 jobject fdObj = env->GetObjectArrayElement(fds, i);
295 if (env->ExceptionOccurred() != NULL) {
296 return -1;
297 }
298 if (fdObj == NULL) {
299 continue;
300 }
301 int fd = jniGetFDFromFileDescriptor(env, fdObj);
302 if (env->ExceptionOccurred() != NULL) {
303 return -1;
304 }
305 if (FD_ISSET(fd, &fdset)) {
306 return (jint)i;
307 }
308 }
309 return -1;
310}
311
312static jobject com_android_internal_os_ZygoteInit_createFileDescriptor (
Elliott Hughes69a017b2011-04-08 14:10:28 -0700313 JNIEnv *env, jobject clazz, jint fd)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314{
315 return jniCreateFileDescriptor(env, fd);
316}
317
318/*
319 * JNI registration.
320 */
321static JNINativeMethod gMethods[] = {
322 /* name, signature, funcPtr */
323 { "setreuid", "(II)I",
324 (void*) com_android_internal_os_ZygoteInit_setreuid },
325 { "setregid", "(II)I",
326 (void*) com_android_internal_os_ZygoteInit_setregid },
327 { "setpgid", "(II)I",
328 (void *) com_android_internal_os_ZygoteInit_setpgid },
329 { "getpgid", "(I)I",
330 (void *) com_android_internal_os_ZygoteInit_getpgid },
Elliott Hughes69a017b2011-04-08 14:10:28 -0700331 { "reopenStdio",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;"
Elliott Hughes69a017b2011-04-08 14:10:28 -0700333 "Ljava/io/FileDescriptor;)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 (void *) com_android_internal_os_ZygoteInit_reopenStdio},
Elliott Hughes69a017b2011-04-08 14:10:28 -0700335 { "closeDescriptor", "(Ljava/io/FileDescriptor;)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 (void *) com_android_internal_os_ZygoteInit_closeDescriptor},
Elliott Hughes69a017b2011-04-08 14:10:28 -0700337 { "setCloseOnExec", "(Ljava/io/FileDescriptor;Z)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338 (void *) com_android_internal_os_ZygoteInit_setCloseOnExec},
Elliott Hughes69a017b2011-04-08 14:10:28 -0700339 { "setCapabilities", "(JJ)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340 (void *) com_android_internal_os_ZygoteInit_setCapabilities },
Elliott Hughes69a017b2011-04-08 14:10:28 -0700341 { "capgetPermitted", "(I)J",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 (void *) com_android_internal_os_ZygoteInit_capgetPermitted },
343 { "selectReadable", "([Ljava/io/FileDescriptor;)I",
344 (void *) com_android_internal_os_ZygoteInit_selectReadable },
345 { "createFileDescriptor", "(I)Ljava/io/FileDescriptor;",
346 (void *) com_android_internal_os_ZygoteInit_createFileDescriptor }
347};
348int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
349{
350 return AndroidRuntime::registerNativeMethods(env,
351 "com/android/internal/os/ZygoteInit", gMethods, NELEM(gMethods));
352}
353
354}; // namespace android