blob: ada4dd339be2e15c14fa3af27a7cf0792b5a452f [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{
48 int err;
49
50 errno = 0;
51 err = setreuid(ruid, euid);
52
53 //LOGI("setreuid(%d,%d) err %d errno %d", ruid, euid, err, errno);
54
55 return errno;
56}
57
58/*
59 * In class com.android.internal.os.ZygoteInit:
60 * private static native int setregid(int rgid, int egid)
61 */
62static jint com_android_internal_os_ZygoteInit_setregid(
63 JNIEnv* env, jobject clazz, jint rgid, jint egid)
64{
65 int err;
66
67 errno = 0;
68 err = setregid(rgid, egid);
69
70 //LOGI("setregid(%d,%d) err %d errno %d", rgid, egid, err, errno);
71
72 return errno;
73}
74
75/*
76 * In class com.android.internal.os.ZygoteInit:
77 * private static native int setpgid(int rgid, int egid)
78 */
79static jint com_android_internal_os_ZygoteInit_setpgid(
80 JNIEnv* env, jobject clazz, jint pid, jint pgid)
81{
82 int err;
83
84 errno = 0;
85
86 err = setpgid(pid, pgid);
87
88 return errno;
89}
90
91/*
92 * In class com.android.internal.os.ZygoteInit:
93 * private static native int getpgid(int pid)
94 */
95static jint com_android_internal_os_ZygoteInit_getpgid(
96 JNIEnv* env, jobject clazz, jint pid)
97{
98 pid_t ret;
99 ret = getpgid(pid);
100
101 if (ret < 0) {
102 jniThrowIOException(env, errno);
103 }
104
105 return ret;
106}
107
108static void com_android_internal_os_ZygoteInit_reopenStdio(JNIEnv* env,
109 jobject clazz, jobject in, jobject out, jobject errfd)
110{
111 int fd;
112 int err;
113
114 fd = jniGetFDFromFileDescriptor(env, in);
115
116 if (env->ExceptionOccurred() != NULL) {
117 return;
118 }
119
120 do {
121 err = dup2(fd, STDIN_FILENO);
122 } while (err < 0 && errno == EINTR);
123
124 fd = jniGetFDFromFileDescriptor(env, out);
125
126 if (env->ExceptionOccurred() != NULL) {
127 return;
128 }
129
130 do {
131 err = dup2(fd, STDOUT_FILENO);
132 } while (err < 0 && errno == EINTR);
133
134 fd = jniGetFDFromFileDescriptor(env, errfd);
135
136 if (env->ExceptionOccurred() != NULL) {
137 return;
138 }
139
140 do {
141 err = dup2(fd, STDERR_FILENO);
142 } while (err < 0 && errno == EINTR);
143}
144
145static void com_android_internal_os_ZygoteInit_closeDescriptor(JNIEnv* env,
146 jobject clazz, jobject descriptor)
147{
148 int fd;
149 int err;
150
151 fd = jniGetFDFromFileDescriptor(env, descriptor);
152
153 if (env->ExceptionOccurred() != NULL) {
154 return;
155 }
156
157 do {
158 err = close(fd);
159 } while (err < 0 && errno == EINTR);
160
161 if (err < 0) {
162 jniThrowIOException(env, errno);
163 return;
164 }
165}
166
167static void com_android_internal_os_ZygoteInit_setCloseOnExec (JNIEnv *env,
168 jobject clazz, jobject descriptor, jboolean flag)
169{
170 int fd;
171 int err;
172 int fdFlags;
173
174 fd = jniGetFDFromFileDescriptor(env, descriptor);
175
176 if (env->ExceptionOccurred() != NULL) {
177 return;
178 }
179
180 fdFlags = fcntl(fd, F_GETFD);
181
182 if (fdFlags < 0) {
183 jniThrowIOException(env, errno);
184 return;
185 }
186
187 if (flag) {
188 fdFlags |= FD_CLOEXEC;
189 } else {
190 fdFlags &= ~FD_CLOEXEC;
191 }
192
193 err = fcntl(fd, F_SETFD, fdFlags);
194
195 if (err < 0) {
196 jniThrowIOException(env, errno);
197 return;
198 }
199}
200
201static void com_android_internal_os_ZygoteInit_setCapabilities (JNIEnv *env,
202 jobject clazz, jlong permitted, jlong effective)
203{
204#ifdef HAVE_ANDROID_OS
205 struct __user_cap_header_struct capheader;
206 struct __user_cap_data_struct capdata;
207 int err;
208
209 memset (&capheader, 0, sizeof(capheader));
210 memset (&capdata, 0, sizeof(capdata));
211
212 capheader.version = _LINUX_CAPABILITY_VERSION;
213 capheader.pid = 0;
214
215 // As of this writing, capdata is __u32, but that's expected
216 // to change...
217 capdata.effective = effective;
218 capdata.permitted = permitted;
219
220 err = capset (&capheader, &capdata);
221
222 if (err < 0) {
223 jniThrowIOException(env, errno);
224 return;
225 }
226#endif /* HAVE_ANDROID_OS */
227}
228
229static jlong com_android_internal_os_ZygoteInit_capgetPermitted (JNIEnv *env,
230 jobject clazz, jint pid)
231{
232#ifndef HAVE_ANDROID_OS
233 return (jlong)0;
234#else
235 struct __user_cap_header_struct capheader;
236 struct __user_cap_data_struct capdata;
237 int err;
238
239 memset (&capheader, 0, sizeof(capheader));
240 memset (&capdata, 0, sizeof(capdata));
241
242 capheader.version = _LINUX_CAPABILITY_VERSION;
243 capheader.pid = pid;
244
245 err = capget (&capheader, &capdata);
246
247 if (err < 0) {
248 jniThrowIOException(env, errno);
249 return 0;
250 }
251
252 return (jlong) capdata.permitted;
253#endif /* HAVE_ANDROID_OS */
254}
255
256static jint com_android_internal_os_ZygoteInit_selectReadable (
257 JNIEnv *env, jobject clazz, jobjectArray fds)
258{
259 if (fds == NULL) {
260 jniThrowException(env, "java/lang/NullPointerException",
261 "fds == null");
262 return -1;
263 }
264
265 jsize length = env->GetArrayLength(fds);
266 fd_set fdset;
267
268 if (env->ExceptionOccurred() != NULL) {
269 return -1;
270 }
271
272 FD_ZERO(&fdset);
273
274 int nfds = 0;
275 for (jsize i = 0; i < length; i++) {
276 jobject fdObj = env->GetObjectArrayElement(fds, i);
277 if (env->ExceptionOccurred() != NULL) {
278 return -1;
279 }
280 if (fdObj == NULL) {
281 continue;
282 }
283 int fd = jniGetFDFromFileDescriptor(env, fdObj);
284 if (env->ExceptionOccurred() != NULL) {
285 return -1;
286 }
287
288 FD_SET(fd, &fdset);
289
290 if (fd >= nfds) {
291 nfds = fd + 1;
292 }
293 }
294
295 int err;
296 do {
297 err = select (nfds, &fdset, NULL, NULL, NULL);
298 } while (err < 0 && errno == EINTR);
299
300 if (err < 0) {
301 jniThrowIOException(env, errno);
302 return -1;
303 }
304
305 for (jsize i = 0; i < length; i++) {
306 jobject fdObj = env->GetObjectArrayElement(fds, i);
307 if (env->ExceptionOccurred() != NULL) {
308 return -1;
309 }
310 if (fdObj == NULL) {
311 continue;
312 }
313 int fd = jniGetFDFromFileDescriptor(env, fdObj);
314 if (env->ExceptionOccurred() != NULL) {
315 return -1;
316 }
317 if (FD_ISSET(fd, &fdset)) {
318 return (jint)i;
319 }
320 }
321 return -1;
322}
323
324static jobject com_android_internal_os_ZygoteInit_createFileDescriptor (
325 JNIEnv *env, jobject clazz, jint fd)
326{
327 return jniCreateFileDescriptor(env, fd);
328}
329
330/*
331 * JNI registration.
332 */
333static JNINativeMethod gMethods[] = {
334 /* name, signature, funcPtr */
335 { "setreuid", "(II)I",
336 (void*) com_android_internal_os_ZygoteInit_setreuid },
337 { "setregid", "(II)I",
338 (void*) com_android_internal_os_ZygoteInit_setregid },
339 { "setpgid", "(II)I",
340 (void *) com_android_internal_os_ZygoteInit_setpgid },
341 { "getpgid", "(I)I",
342 (void *) com_android_internal_os_ZygoteInit_getpgid },
343 { "reopenStdio",
344 "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;"
345 "Ljava/io/FileDescriptor;)V",
346 (void *) com_android_internal_os_ZygoteInit_reopenStdio},
347 { "closeDescriptor", "(Ljava/io/FileDescriptor;)V",
348 (void *) com_android_internal_os_ZygoteInit_closeDescriptor},
349 { "setCloseOnExec", "(Ljava/io/FileDescriptor;Z)V",
350 (void *) com_android_internal_os_ZygoteInit_setCloseOnExec},
351 { "setCapabilities", "(JJ)V",
352 (void *) com_android_internal_os_ZygoteInit_setCapabilities },
353 { "capgetPermitted", "(I)J",
354 (void *) com_android_internal_os_ZygoteInit_capgetPermitted },
355 { "selectReadable", "([Ljava/io/FileDescriptor;)I",
356 (void *) com_android_internal_os_ZygoteInit_selectReadable },
357 { "createFileDescriptor", "(I)Ljava/io/FileDescriptor;",
358 (void *) com_android_internal_os_ZygoteInit_createFileDescriptor }
359};
360int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
361{
362 return AndroidRuntime::registerNativeMethods(env,
363 "com/android/internal/os/ZygoteInit", gMethods, NELEM(gMethods));
364}
365
366}; // namespace android
367