com_android_internal_os_ZygoteInit.cpp revision ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3
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_setCloseOnExec (JNIEnv *env,
135    jobject clazz, jobject descriptor, jboolean flag)
136{
137    int fd;
138    int err;
139    int fdFlags;
140
141    fd = jniGetFDFromFileDescriptor(env, descriptor);
142
143    if  (env->ExceptionOccurred() != NULL) {
144        return;
145    }
146
147    fdFlags = fcntl(fd, F_GETFD);
148
149    if (fdFlags < 0) {
150        jniThrowIOException(env, errno);
151        return;
152    }
153
154    if (flag) {
155        fdFlags |= FD_CLOEXEC;
156    } else {
157        fdFlags &= ~FD_CLOEXEC;
158    }
159
160    err = fcntl(fd, F_SETFD, fdFlags);
161
162    if (err < 0) {
163        jniThrowIOException(env, errno);
164        return;
165    }
166}
167
168static void com_android_internal_os_ZygoteInit_setCapabilities (JNIEnv *env,
169    jobject clazz, jlong permitted, jlong effective)
170{
171#ifdef HAVE_ANDROID_OS
172    struct __user_cap_header_struct capheader;
173    struct __user_cap_data_struct capdata;
174    int err;
175
176    memset (&capheader, 0, sizeof(capheader));
177    memset (&capdata, 0, sizeof(capdata));
178
179    capheader.version = _LINUX_CAPABILITY_VERSION;
180    capheader.pid = 0;
181
182    // As of this writing, capdata is __u32, but that's expected
183    // to change...
184    capdata.effective = effective;
185    capdata.permitted = permitted;
186
187    err = capset (&capheader, &capdata);
188
189    if (err < 0) {
190        jniThrowIOException(env, errno);
191        return;
192    }
193#endif /* HAVE_ANDROID_OS */
194}
195
196static jlong com_android_internal_os_ZygoteInit_capgetPermitted (JNIEnv *env,
197    jobject clazz, jint pid)
198{
199#ifndef HAVE_ANDROID_OS
200    return (jlong)0;
201#else
202    struct __user_cap_header_struct capheader;
203    struct __user_cap_data_struct capdata;
204    int err;
205
206    memset (&capheader, 0, sizeof(capheader));
207    memset (&capdata, 0, sizeof(capdata));
208
209    capheader.version = _LINUX_CAPABILITY_VERSION;
210    capheader.pid = pid;
211
212    err = capget (&capheader, &capdata);
213
214    if (err < 0) {
215        jniThrowIOException(env, errno);
216        return 0;
217    }
218
219    return (jlong) capdata.permitted;
220#endif /* HAVE_ANDROID_OS */
221}
222
223static jint com_android_internal_os_ZygoteInit_selectReadable (
224        JNIEnv *env, jobject clazz, jobjectArray fds)
225{
226    if (fds == NULL) {
227        jniThrowNullPointerException(env, "fds == null");
228        return -1;
229    }
230
231    jsize length = env->GetArrayLength(fds);
232    fd_set fdset;
233
234    if (env->ExceptionOccurred() != NULL) {
235        return -1;
236    }
237
238    FD_ZERO(&fdset);
239
240    int nfds = 0;
241    for (jsize i = 0; i < length; i++) {
242        jobject fdObj = env->GetObjectArrayElement(fds, i);
243        if  (env->ExceptionOccurred() != NULL) {
244            return -1;
245        }
246        if (fdObj == NULL) {
247            continue;
248        }
249        int fd = jniGetFDFromFileDescriptor(env, fdObj);
250        if  (env->ExceptionOccurred() != NULL) {
251            return -1;
252        }
253
254        FD_SET(fd, &fdset);
255
256        if (fd >= nfds) {
257            nfds = fd + 1;
258        }
259    }
260
261    int err;
262    do {
263        err = select (nfds, &fdset, NULL, NULL, NULL);
264    } while (err < 0 && errno == EINTR);
265
266    if (err < 0) {
267        jniThrowIOException(env, errno);
268        return -1;
269    }
270
271    for (jsize i = 0; i < length; i++) {
272        jobject fdObj = env->GetObjectArrayElement(fds, i);
273        if  (env->ExceptionOccurred() != NULL) {
274            return -1;
275        }
276        if (fdObj == NULL) {
277            continue;
278        }
279        int fd = jniGetFDFromFileDescriptor(env, fdObj);
280        if  (env->ExceptionOccurred() != NULL) {
281            return -1;
282        }
283        if (FD_ISSET(fd, &fdset)) {
284            return (jint)i;
285        }
286    }
287    return -1;
288}
289
290static jobject com_android_internal_os_ZygoteInit_createFileDescriptor (
291        JNIEnv *env, jobject clazz, jint fd)
292{
293    return jniCreateFileDescriptor(env, fd);
294}
295
296/*
297 * JNI registration.
298 */
299static JNINativeMethod gMethods[] = {
300    /* name, signature, funcPtr */
301    { "setreuid", "(II)I",
302      (void*) com_android_internal_os_ZygoteInit_setreuid },
303    { "setregid", "(II)I",
304      (void*) com_android_internal_os_ZygoteInit_setregid },
305    { "setpgid", "(II)I",
306      (void *) com_android_internal_os_ZygoteInit_setpgid },
307    { "getpgid", "(I)I",
308      (void *) com_android_internal_os_ZygoteInit_getpgid },
309    { "reopenStdio",
310        "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;"
311        "Ljava/io/FileDescriptor;)V",
312            (void *) com_android_internal_os_ZygoteInit_reopenStdio},
313    { "setCloseOnExec", "(Ljava/io/FileDescriptor;Z)V",
314        (void *)  com_android_internal_os_ZygoteInit_setCloseOnExec},
315    { "setCapabilities", "(JJ)V",
316        (void *) com_android_internal_os_ZygoteInit_setCapabilities },
317    { "capgetPermitted", "(I)J",
318        (void *) com_android_internal_os_ZygoteInit_capgetPermitted },
319    { "selectReadable", "([Ljava/io/FileDescriptor;)I",
320        (void *) com_android_internal_os_ZygoteInit_selectReadable },
321    { "createFileDescriptor", "(I)Ljava/io/FileDescriptor;",
322        (void *) com_android_internal_os_ZygoteInit_createFileDescriptor }
323};
324int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
325{
326    return AndroidRuntime::registerNativeMethods(env,
327            "com/android/internal/os/ZygoteInit", gMethods, NELEM(gMethods));
328}
329
330}; // namespace android
331