com_android_internal_os_ZygoteInit.cpp revision 69a017bc1d1649350f830dfada5c6ed5eac0b770
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#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    if (setreuid(ruid, euid) < 0) {
49        return errno;
50    }
51    return 0;
52}
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{
61    if (setregid(rgid, egid) < 0) {
62        return errno;
63    }
64    return 0;
65}
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{
74    if (setpgid(pid, pgid) < 0) {
75        return errno;
76    }
77    return 0;
78}
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
97static void com_android_internal_os_ZygoteInit_reopenStdio(JNIEnv* env,
98        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
134static void com_android_internal_os_ZygoteInit_closeDescriptor(JNIEnv* env,
135        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
209    err = capset (&capheader, &capdata);
210
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
234    err = capget (&capheader, &capdata);
235
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 (
246        JNIEnv *env, jobject clazz, jobjectArray fds)
247{
248    if (fds == NULL) {
249        jniThrowNullPointerException(env, "fds == null");
250        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 (
313        JNIEnv *env, jobject clazz, jint fd)
314{
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 },
331    { "reopenStdio",
332        "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;"
333        "Ljava/io/FileDescriptor;)V",
334            (void *) com_android_internal_os_ZygoteInit_reopenStdio},
335    { "closeDescriptor", "(Ljava/io/FileDescriptor;)V",
336        (void *) com_android_internal_os_ZygoteInit_closeDescriptor},
337    { "setCloseOnExec", "(Ljava/io/FileDescriptor;Z)V",
338        (void *)  com_android_internal_os_ZygoteInit_setCloseOnExec},
339    { "setCapabilities", "(JJ)V",
340        (void *) com_android_internal_os_ZygoteInit_setCapabilities },
341    { "capgetPermitted", "(I)J",
342        (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
355