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