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 <linux/capability.h>
31#include <linux/prctl.h>
32#include <sys/prctl.h>
33extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
34extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
35
36
37namespace android {
38
39/*
40 * In class com.android.internal.os.ZygoteInit:
41 * private static native boolean setreuid(int ruid, int euid)
42 */
43static jint com_android_internal_os_ZygoteInit_setreuid(
44    JNIEnv* env, jobject clazz, jint ruid, jint euid)
45{
46    if (setreuid(ruid, euid) < 0) {
47        return errno;
48    }
49    return 0;
50}
51
52/*
53 * In class com.android.internal.os.ZygoteInit:
54 * private static native int setregid(int rgid, int egid)
55 */
56static jint com_android_internal_os_ZygoteInit_setregid(
57    JNIEnv* env, jobject clazz, jint rgid, jint egid)
58{
59    if (setregid(rgid, egid) < 0) {
60        return errno;
61    }
62    return 0;
63}
64
65/*
66 * In class com.android.internal.os.ZygoteInit:
67 * private static native int setpgid(int rgid, int egid)
68 */
69static jint com_android_internal_os_ZygoteInit_setpgid(
70    JNIEnv* env, jobject clazz, jint pid, jint pgid)
71{
72    if (setpgid(pid, pgid) < 0) {
73        return errno;
74    }
75    return 0;
76}
77
78/*
79 * In class com.android.internal.os.ZygoteInit:
80 * private static native int getpgid(int pid)
81 */
82static jint com_android_internal_os_ZygoteInit_getpgid(
83    JNIEnv* env, jobject clazz, jint pid)
84{
85    pid_t ret;
86    ret = getpgid(pid);
87
88    if (ret < 0) {
89        jniThrowIOException(env, errno);
90    }
91
92    return ret;
93}
94
95static void com_android_internal_os_ZygoteInit_reopenStdio(JNIEnv* env,
96        jobject clazz, jobject in, jobject out, jobject errfd)
97{
98    int fd;
99    int err;
100
101    fd = jniGetFDFromFileDescriptor(env, in);
102
103    if  (env->ExceptionOccurred() != NULL) {
104        return;
105    }
106
107    do {
108        err = dup2(fd, STDIN_FILENO);
109    } while (err < 0 && errno == EINTR);
110
111    fd = jniGetFDFromFileDescriptor(env, out);
112
113    if  (env->ExceptionOccurred() != NULL) {
114        return;
115    }
116
117    do {
118        err = dup2(fd, STDOUT_FILENO);
119    } while (err < 0 && errno == EINTR);
120
121    fd = jniGetFDFromFileDescriptor(env, errfd);
122
123    if  (env->ExceptionOccurred() != NULL) {
124        return;
125    }
126
127    do {
128        err = dup2(fd, STDERR_FILENO);
129    } while (err < 0 && errno == EINTR);
130}
131
132static void com_android_internal_os_ZygoteInit_setCloseOnExec (JNIEnv *env,
133    jobject clazz, jobject descriptor, jboolean flag)
134{
135    int fd;
136    int err;
137    int fdFlags;
138
139    fd = jniGetFDFromFileDescriptor(env, descriptor);
140
141    if  (env->ExceptionOccurred() != NULL) {
142        return;
143    }
144
145    fdFlags = fcntl(fd, F_GETFD);
146
147    if (fdFlags < 0) {
148        jniThrowIOException(env, errno);
149        return;
150    }
151
152    if (flag) {
153        fdFlags |= FD_CLOEXEC;
154    } else {
155        fdFlags &= ~FD_CLOEXEC;
156    }
157
158    err = fcntl(fd, F_SETFD, fdFlags);
159
160    if (err < 0) {
161        jniThrowIOException(env, errno);
162        return;
163    }
164}
165
166static void com_android_internal_os_ZygoteInit_setCapabilities (JNIEnv *env,
167    jobject clazz, jlong permitted, jlong effective)
168{
169    struct __user_cap_header_struct capheader;
170    struct __user_cap_data_struct capdata;
171    int err;
172
173    memset (&capheader, 0, sizeof(capheader));
174    memset (&capdata, 0, sizeof(capdata));
175
176    capheader.version = _LINUX_CAPABILITY_VERSION;
177    capheader.pid = 0;
178
179    // As of this writing, capdata is __u32, but that's expected
180    // to change...
181    capdata.effective = effective;
182    capdata.permitted = permitted;
183
184    err = capset (&capheader, &capdata);
185
186    if (err < 0) {
187        jniThrowIOException(env, errno);
188        return;
189    }
190}
191
192static jlong com_android_internal_os_ZygoteInit_capgetPermitted (JNIEnv *env,
193    jobject clazz, jint pid)
194{
195    struct __user_cap_header_struct capheader;
196    struct __user_cap_data_struct capdata;
197    int err;
198
199    memset (&capheader, 0, sizeof(capheader));
200    memset (&capdata, 0, sizeof(capdata));
201
202    capheader.version = _LINUX_CAPABILITY_VERSION;
203    capheader.pid = pid;
204
205    err = capget (&capheader, &capdata);
206
207    if (err < 0) {
208        jniThrowIOException(env, errno);
209        return 0;
210    }
211
212    return (jlong) capdata.permitted;
213}
214
215static jint com_android_internal_os_ZygoteInit_selectReadable (
216        JNIEnv *env, jobject clazz, jobjectArray fds)
217{
218    if (fds == NULL) {
219        jniThrowNullPointerException(env, "fds == null");
220        return -1;
221    }
222
223    jsize length = env->GetArrayLength(fds);
224    fd_set fdset;
225
226    if (env->ExceptionOccurred() != NULL) {
227        return -1;
228    }
229
230    FD_ZERO(&fdset);
231
232    int nfds = 0;
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
246        FD_SET(fd, &fdset);
247
248        if (fd >= nfds) {
249            nfds = fd + 1;
250        }
251    }
252
253    int err;
254    do {
255        err = select (nfds, &fdset, NULL, NULL, NULL);
256    } while (err < 0 && errno == EINTR);
257
258    if (err < 0) {
259        jniThrowIOException(env, errno);
260        return -1;
261    }
262
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        if (FD_ISSET(fd, &fdset)) {
276            return (jint)i;
277        }
278    }
279    return -1;
280}
281
282static jobject com_android_internal_os_ZygoteInit_createFileDescriptor (
283        JNIEnv *env, jobject clazz, jint fd)
284{
285    return jniCreateFileDescriptor(env, fd);
286}
287
288/*
289 * JNI registration.
290 */
291static JNINativeMethod gMethods[] = {
292    /* name, signature, funcPtr */
293    { "setreuid", "(II)I",
294      (void*) com_android_internal_os_ZygoteInit_setreuid },
295    { "setregid", "(II)I",
296      (void*) com_android_internal_os_ZygoteInit_setregid },
297    { "setpgid", "(II)I",
298      (void *) com_android_internal_os_ZygoteInit_setpgid },
299    { "getpgid", "(I)I",
300      (void *) com_android_internal_os_ZygoteInit_getpgid },
301    { "reopenStdio",
302        "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;"
303        "Ljava/io/FileDescriptor;)V",
304            (void *) com_android_internal_os_ZygoteInit_reopenStdio},
305    { "setCloseOnExec", "(Ljava/io/FileDescriptor;Z)V",
306        (void *)  com_android_internal_os_ZygoteInit_setCloseOnExec},
307    { "setCapabilities", "(JJ)V",
308        (void *) com_android_internal_os_ZygoteInit_setCapabilities },
309    { "capgetPermitted", "(I)J",
310        (void *) com_android_internal_os_ZygoteInit_capgetPermitted },
311    { "selectReadable", "([Ljava/io/FileDescriptor;)I",
312        (void *) com_android_internal_os_ZygoteInit_selectReadable },
313    { "createFileDescriptor", "(I)Ljava/io/FileDescriptor;",
314        (void *) com_android_internal_os_ZygoteInit_createFileDescriptor }
315};
316int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
317{
318    return AndroidRuntime::registerNativeMethods(env,
319            "com/android/internal/os/ZygoteInit", gMethods, NELEM(gMethods));
320}
321
322}; // namespace android
323