File: | jdk/src/java.base/unix/native/libjava/ProcessImpl_md.c |
Warning: | line 459, column 17 Call to function 'vfork' is insecure as it can lead to denial of service situations in the parent process. Replace calls to vfork with calls to the safer 'posix_spawn' function |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved. |
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | * |
5 | * This code is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License version 2 only, as |
7 | * published by the Free Software Foundation. Oracle designates this |
8 | * particular file as subject to the "Classpath" exception as provided |
9 | * by Oracle in the LICENSE file that accompanied this code. |
10 | * |
11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | * version 2 for more details (a copy is included in the LICENSE file that |
15 | * accompanied this code). |
16 | * |
17 | * You should have received a copy of the GNU General Public License version |
18 | * 2 along with this work; if not, write to the Free Software Foundation, |
19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
20 | * |
21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
22 | * or visit www.oracle.com if you need additional information or have any |
23 | * questions. |
24 | */ |
25 | |
26 | #undef _LARGEFILE64_SOURCE1 |
27 | #define _LARGEFILE64_SOURCE1 1 |
28 | |
29 | #include "jni.h" |
30 | #include "jvm.h" |
31 | #include "jvm_md.h" |
32 | #include "jni_util.h" |
33 | #include "io_util.h" |
34 | |
35 | /* |
36 | * Platform-specific support for java.lang.Process |
37 | */ |
38 | #include <assert.h> |
39 | #include <stddef.h> |
40 | #include <stdlib.h> |
41 | #include <sys/types.h> |
42 | #include <ctype.h> |
43 | #include <sys/wait.h> |
44 | #include <signal.h> |
45 | #include <string.h> |
46 | |
47 | #include <spawn.h> |
48 | |
49 | #include "childproc.h" |
50 | |
51 | /* |
52 | * |
53 | * When starting a child on Unix, we need to do three things: |
54 | * - fork off |
55 | * - in the child process, do some pre-exec work: duping/closing file |
56 | * descriptors to set up stdio-redirection, setting environment variables, |
57 | * changing paths... |
58 | * - then exec(2) the target binary |
59 | * |
60 | * There are three ways to fork off: |
61 | * |
62 | * A) fork(2). Portable and safe (no side effects) but may fail with ENOMEM on |
63 | * all Unices when invoked from a VM with a high memory footprint. On Unices |
64 | * with strict no-overcommit policy this problem is most visible. |
65 | * |
66 | * This is because forking the VM will first create a child process with |
67 | * theoretically the same memory footprint as the parent - even if you plan |
68 | * to follow up with exec'ing a tiny binary. In reality techniques like |
69 | * copy-on-write etc mitigate the problem somewhat but we still run the risk |
70 | * of hitting system limits. |
71 | * |
72 | * For a Linux centric description of this problem, see the documentation on |
73 | * /proc/sys/vm/overcommit_memory in Linux proc(5). |
74 | * |
75 | * B) vfork(2): Portable and fast but very unsafe. It bypasses the memory |
76 | * problems related to fork(2) by starting the child in the memory image of |
77 | * the parent. Things that can go wrong include: |
78 | * - Programming errors in the child process before the exec(2) call may |
79 | * trash memory in the parent process, most commonly the stack of the |
80 | * thread invoking vfork. |
81 | * - Signals received by the child before the exec(2) call may be at best |
82 | * misdirected to the parent, at worst immediately kill child and parent. |
83 | * |
84 | * This is mitigated by very strict rules about what one is allowed to do in |
85 | * the child process between vfork(2) and exec(2), which is basically nothing. |
86 | * However, we always broke this rule by doing the pre-exec work between |
87 | * vfork(2) and exec(2). |
88 | * |
89 | * Also note that vfork(2) has been deprecated by the OpenGroup, presumably |
90 | * because of its many dangers. |
91 | * |
92 | * C) clone(2): This is a Linux specific call which gives the caller fine |
93 | * grained control about how exactly the process fork is executed. It is |
94 | * powerful, but Linux-specific. |
95 | * |
96 | * Aside from these three possibilities there is a forth option: posix_spawn(3). |
97 | * Where fork/vfork/clone all fork off the process and leave pre-exec work and |
98 | * calling exec(2) to the user, posix_spawn(3) offers the user fork+exec-like |
99 | * functionality in one package, similar to CreateProcess() on Windows. |
100 | * |
101 | * It is not a system call in itself, but usually a wrapper implemented within |
102 | * the libc in terms of one of (fork|vfork|clone)+exec - so whether or not it |
103 | * has advantages over calling the naked (fork|vfork|clone) functions depends |
104 | * on how posix_spawn(3) is implemented. |
105 | * |
106 | * Note that when using posix_spawn(3), we exec twice: first a tiny binary called |
107 | * the jspawnhelper, then in the jspawnhelper we do the pre-exec work and exec a |
108 | * second time, this time the target binary (similar to the "exec-twice-technique" |
109 | * described in http://mail.openjdk.java.net/pipermail/core-libs-dev/2018-September/055333.html). |
110 | * |
111 | * This is a JDK-specific implementation detail which just happens to be |
112 | * implemented for jdk.lang.Process.launchMechanism=POSIX_SPAWN. |
113 | * |
114 | * --- Linux-specific --- |
115 | * |
116 | * How does glibc implement posix_spawn? |
117 | * (see: sysdeps/posix/spawni.c for glibc < 2.24, |
118 | * sysdeps/unix/sysv/linux/spawni.c for glibc >= 2.24): |
119 | * |
120 | * 1) Before glibc 2.4 (released 2006), posix_spawn(3) used just fork(2)/exec(2). |
121 | * This would be bad for the JDK since we would risk the known memory issues with |
122 | * fork(2). But since this only affects glibc variants which have long been |
123 | * phased out by modern distributions, this is irrelevant. |
124 | * |
125 | * 2) Between glibc 2.4 and glibc 2.23, posix_spawn uses either fork(2) or |
126 | * vfork(2) depending on how exactly the user called posix_spawn(3): |
127 | * |
128 | * <quote> |
129 | * The child process is created using vfork(2) instead of fork(2) when |
130 | * either of the following is true: |
131 | * |
132 | * * the spawn-flags element of the attributes object pointed to by |
133 | * attrp contains the GNU-specific flag POSIX_SPAWN_USEVFORK; or |
134 | * |
135 | * * file_actions is NULL and the spawn-flags element of the attributes |
136 | * object pointed to by attrp does not contain |
137 | * POSIX_SPAWN_SETSIGMASK, POSIX_SPAWN_SETSIGDEF, |
138 | * POSIX_SPAWN_SETSCHEDPARAM, POSIX_SPAWN_SETSCHEDULER, |
139 | * POSIX_SPAWN_SETPGROUP, or POSIX_SPAWN_RESETIDS. |
140 | * </quote> |
141 | * |
142 | * Due to the way the JDK calls posix_spawn(3), it would therefore call vfork(2). |
143 | * So we would avoid the fork(2) memory problems. However, there still remains the |
144 | * risk associated with vfork(2). But it is smaller than were we to call vfork(2) |
145 | * directly since we use the jspawnhelper, moving all pre-exec work off to after |
146 | * the first exec, thereby reducing the vulnerable time window. |
147 | * |
148 | * 3) Since glibc >= 2.24, glibc uses clone+exec: |
149 | * |
150 | * new_pid = CLONE (__spawni_child, STACK (stack, stack_size), stack_size, |
151 | * CLONE_VM | CLONE_VFORK | SIGCHLD, &args); |
152 | * |
153 | * This is even better than (2): |
154 | * |
155 | * CLONE_VM means we run in the parent's memory image, as with (2) |
156 | * CLONE_VFORK means parent waits until we exec, as with (2) |
157 | * |
158 | * However, error possibilities are further reduced since: |
159 | * - posix_spawn(3) passes a separate stack for the child to run on, eliminating |
160 | * the danger of trashing the forking thread's stack in the parent process. |
161 | * - posix_spawn(3) takes care to temporarily block all incoming signals to the |
162 | * child process until the first exec(2) has been called, |
163 | * |
164 | * TL;DR |
165 | * Calling posix_spawn(3) for glibc |
166 | * (2) < 2.24 is not perfect but still better than using plain vfork(2), since |
167 | * the chance of an error happening is greatly reduced |
168 | * (3) >= 2.24 is the best option - portable, fast and as safe as possible. |
169 | * |
170 | * --- |
171 | * |
172 | * How does muslc implement posix_spawn? |
173 | * |
174 | * They always did use the clone (.. CLONE_VM | CLONE_VFORK ...) |
175 | * technique. So we are safe to use posix_spawn() here regardless of muslc |
176 | * version. |
177 | * |
178 | * </Linux-specific> |
179 | * |
180 | * |
181 | * Based on the above analysis, we are currently defaulting to posix_spawn() |
182 | * on all Unices including Linux. |
183 | */ |
184 | |
185 | static void |
186 | setSIGCHLDHandler(JNIEnv *env) |
187 | { |
188 | /* There is a subtle difference between having the signal handler |
189 | * for SIGCHLD be SIG_DFL and SIG_IGN. We cannot obtain process |
190 | * termination information for child processes if the signal |
191 | * handler is SIG_IGN. It must be SIG_DFL. |
192 | * |
193 | * We used to set the SIGCHLD handler only on Linux, but it's |
194 | * safest to set it unconditionally. |
195 | * |
196 | * Consider what happens if java's parent process sets the SIGCHLD |
197 | * handler to SIG_IGN. Normally signal handlers are inherited by |
198 | * children, but SIGCHLD is a controversial case. Solaris appears |
199 | * to always reset it to SIG_DFL, but this behavior may be |
200 | * non-standard-compliant, and we shouldn't rely on it. |
201 | * |
202 | * References: |
203 | * http://www.opengroup.org/onlinepubs/7908799/xsh/exec.html |
204 | * http://www.pasc.org/interps/unofficial/db/p1003.1/pasc-1003.1-132.html |
205 | */ |
206 | struct sigaction sa; |
207 | sa.sa_handler__sigaction_handler.sa_handler = SIG_DFL((__sighandler_t) 0); |
208 | sigemptyset(&sa.sa_mask); |
209 | sa.sa_flags = SA_NOCLDSTOP1 | SA_RESTART0x10000000; |
210 | if (sigaction(SIGCHLD17, &sa, NULL((void*)0)) < 0) |
211 | JNU_ThrowInternalError(env, "Can't set SIGCHLD handler"); |
212 | } |
213 | |
214 | static void* |
215 | xmalloc(JNIEnv *env, size_t size) |
216 | { |
217 | void *p = malloc(size); |
218 | if (p == NULL((void*)0)) |
219 | JNU_ThrowOutOfMemoryError(env, NULL((void*)0)); |
220 | return p; |
221 | } |
222 | |
223 | #define NEW(type, n)((type *) xmalloc(env, (n) * sizeof(type))) ((type *) xmalloc(env, (n) * sizeof(type))) |
224 | |
225 | /** |
226 | * If PATH is not defined, the OS provides some default value. |
227 | * Unfortunately, there's no portable way to get this value. |
228 | * Fortunately, it's only needed if the child has PATH while we do not. |
229 | */ |
230 | static const char* |
231 | defaultPath(void) |
232 | { |
233 | return ":/bin:/usr/bin"; |
234 | } |
235 | |
236 | static const char* |
237 | effectivePath(void) |
238 | { |
239 | const char *s = getenv("PATH"); |
240 | return (s != NULL((void*)0)) ? s : defaultPath(); |
241 | } |
242 | |
243 | static int |
244 | countOccurrences(const char *s, char c) |
245 | { |
246 | int count; |
247 | for (count = 0; *s != '\0'; s++) |
248 | count += (*s == c); |
249 | return count; |
250 | } |
251 | |
252 | static const char * const * |
253 | effectivePathv(JNIEnv *env) |
254 | { |
255 | char *p; |
256 | int i; |
257 | const char *path = effectivePath(); |
258 | int count = countOccurrences(path, ':') + 1; |
259 | size_t pathvsize = sizeof(const char *) * (count+1); |
260 | size_t pathsize = strlen(path) + 1; |
261 | const char **pathv = (const char **) xmalloc(env, pathvsize + pathsize); |
262 | |
263 | if (pathv == NULL((void*)0)) |
264 | return NULL((void*)0); |
265 | p = (char *) pathv + pathvsize; |
266 | memcpy(p, path, pathsize); |
267 | /* split PATH by replacing ':' with NULs; empty components => "." */ |
268 | for (i = 0; i < count; i++) { |
269 | char *q = p + strcspn(p, ":"); |
270 | pathv[i] = (p == q) ? "." : p; |
271 | *q = '\0'; |
272 | p = q + 1; |
273 | } |
274 | pathv[count] = NULL((void*)0); |
275 | return pathv; |
276 | } |
277 | |
278 | JNIEXPORT__attribute__((visibility("default"))) void JNICALL |
279 | Java_java_lang_ProcessImpl_init(JNIEnv *env, jclass clazz) |
280 | { |
281 | parentPathv = effectivePathv(env); |
282 | CHECK_NULL(parentPathv)do { if ((parentPathv) == ((void*)0)) { return; } } while (0); |
283 | setSIGCHLDHandler(env); |
284 | } |
285 | |
286 | |
287 | #ifndef WIFEXITED |
288 | #define WIFEXITED(status)(((status) & 0x7f) == 0) (((status)&0xFF) == 0) |
289 | #endif |
290 | |
291 | #ifndef WEXITSTATUS |
292 | #define WEXITSTATUS(status)(((status) & 0xff00) >> 8) (((status)>>8)&0xFF) |
293 | #endif |
294 | |
295 | #ifndef WIFSIGNALED |
296 | #define WIFSIGNALED(status)(((signed char) (((status) & 0x7f) + 1) >> 1) > 0 ) (((status)&0xFF) > 0 && ((status)&0xFF00) == 0) |
297 | #endif |
298 | |
299 | #ifndef WTERMSIG |
300 | #define WTERMSIG(status)((status) & 0x7f) ((status)&0x7F) |
301 | #endif |
302 | |
303 | static const char * |
304 | getBytes(JNIEnv *env, jbyteArray arr) |
305 | { |
306 | return arr == NULL((void*)0) ? NULL((void*)0) : |
307 | (const char*) (*env)->GetByteArrayElements(env, arr, NULL((void*)0)); |
308 | } |
309 | |
310 | static void |
311 | releaseBytes(JNIEnv *env, jbyteArray arr, const char* parr) |
312 | { |
313 | if (parr != NULL((void*)0)) |
314 | (*env)->ReleaseByteArrayElements(env, arr, (jbyte*) parr, JNI_ABORT2); |
315 | } |
316 | |
317 | #define IOE_FORMAT"error=%d, %s" "error=%d, %s" |
318 | |
319 | static void |
320 | throwIOException(JNIEnv *env, int errnum, const char *defaultDetail) |
321 | { |
322 | const char *detail = defaultDetail; |
323 | char *errmsg; |
324 | size_t fmtsize; |
325 | char tmpbuf[1024]; |
326 | jstring s; |
327 | |
328 | if (errnum != 0) { |
329 | int ret = getErrorString(errnum, tmpbuf, sizeof(tmpbuf)); |
330 | if (ret != EINVAL22) |
331 | detail = tmpbuf; |
332 | } |
333 | /* ASCII Decimal representation uses 2.4 times as many bits as binary. */ |
334 | fmtsize = sizeof(IOE_FORMAT"error=%d, %s") + strlen(detail) + 3 * sizeof(errnum); |
335 | errmsg = NEW(char, fmtsize)((char *) xmalloc(env, (fmtsize) * sizeof(char))); |
336 | if (errmsg == NULL((void*)0)) |
337 | return; |
338 | |
339 | snprintf(errmsg, fmtsize, IOE_FORMAT, errnum, detail)__builtin___snprintf_chk (errmsg, fmtsize, 2 - 1, __builtin_object_size (errmsg, 2 > 1), "error=%d, %s", errnum, detail); |
340 | s = JNU_NewStringPlatform(env, errmsg); |
341 | if (s != NULL((void*)0)) { |
342 | jobject x = JNU_NewObjectByName(env, "java/io/IOException", |
343 | "(Ljava/lang/String;)V", s); |
344 | if (x != NULL((void*)0)) |
345 | (*env)->Throw(env, x); |
346 | } |
347 | free(errmsg); |
348 | } |
349 | |
350 | /** |
351 | * Throws an IOException with a message composed from the result of waitpid status. |
352 | */ |
353 | static void throwExitCause(JNIEnv *env, int pid, int status) { |
354 | char ebuf[128]; |
355 | if (WIFEXITED(status)(((status) & 0x7f) == 0)) { |
356 | snprintf(ebuf, sizeof ebuf,__builtin___snprintf_chk (ebuf, sizeof ebuf, 2 - 1, __builtin_object_size (ebuf, 2 > 1), "Failed to exec spawn helper: pid: %d, exit value: %d" , pid, (((status) & 0xff00) >> 8)) |
357 | "Failed to exec spawn helper: pid: %d, exit value: %d",__builtin___snprintf_chk (ebuf, sizeof ebuf, 2 - 1, __builtin_object_size (ebuf, 2 > 1), "Failed to exec spawn helper: pid: %d, exit value: %d" , pid, (((status) & 0xff00) >> 8)) |
358 | pid, WEXITSTATUS(status))__builtin___snprintf_chk (ebuf, sizeof ebuf, 2 - 1, __builtin_object_size (ebuf, 2 > 1), "Failed to exec spawn helper: pid: %d, exit value: %d" , pid, (((status) & 0xff00) >> 8)); |
359 | } else if (WIFSIGNALED(status)(((signed char) (((status) & 0x7f) + 1) >> 1) > 0 )) { |
360 | snprintf(ebuf, sizeof ebuf,__builtin___snprintf_chk (ebuf, sizeof ebuf, 2 - 1, __builtin_object_size (ebuf, 2 > 1), "Failed to exec spawn helper: pid: %d, signal: %d" , pid, ((status) & 0x7f)) |
361 | "Failed to exec spawn helper: pid: %d, signal: %d",__builtin___snprintf_chk (ebuf, sizeof ebuf, 2 - 1, __builtin_object_size (ebuf, 2 > 1), "Failed to exec spawn helper: pid: %d, signal: %d" , pid, ((status) & 0x7f)) |
362 | pid, WTERMSIG(status))__builtin___snprintf_chk (ebuf, sizeof ebuf, 2 - 1, __builtin_object_size (ebuf, 2 > 1), "Failed to exec spawn helper: pid: %d, signal: %d" , pid, ((status) & 0x7f)); |
363 | } else { |
364 | snprintf(ebuf, sizeof ebuf,__builtin___snprintf_chk (ebuf, sizeof ebuf, 2 - 1, __builtin_object_size (ebuf, 2 > 1), "Failed to exec spawn helper: pid: %d, status: 0x%08x" , pid, status) |
365 | "Failed to exec spawn helper: pid: %d, status: 0x%08x",__builtin___snprintf_chk (ebuf, sizeof ebuf, 2 - 1, __builtin_object_size (ebuf, 2 > 1), "Failed to exec spawn helper: pid: %d, status: 0x%08x" , pid, status) |
366 | pid, status)__builtin___snprintf_chk (ebuf, sizeof ebuf, 2 - 1, __builtin_object_size (ebuf, 2 > 1), "Failed to exec spawn helper: pid: %d, status: 0x%08x" , pid, status); |
367 | } |
368 | throwIOException(env, 0, ebuf); |
369 | } |
370 | |
371 | #ifdef DEBUG_PROCESS |
372 | /* Debugging process code is difficult; where to write debug output? */ |
373 | static void |
374 | debugPrint(char *format, ...) |
375 | { |
376 | FILE *tty = fopen("/dev/tty", "w"); |
377 | va_list ap; |
378 | va_start(ap, format)__builtin_va_start(ap, format); |
379 | vfprintf(tty, format, ap); |
380 | va_end(ap)__builtin_va_end(ap); |
381 | fclose(tty); |
382 | } |
383 | #endif /* DEBUG_PROCESS */ |
384 | |
385 | static void |
386 | copyPipe(int from[2], int to[2]) |
387 | { |
388 | to[0] = from[0]; |
389 | to[1] = from[1]; |
390 | } |
391 | |
392 | /* arg is an array of pointers to 0 terminated strings. array is terminated |
393 | * by a null element. |
394 | * |
395 | * *nelems and *nbytes receive the number of elements of array (incl 0) |
396 | * and total number of bytes (incl. 0) |
397 | * Note. An empty array will have one null element |
398 | * But if arg is null, then *nelems set to 0, and *nbytes to 0 |
399 | */ |
400 | static void arraysize(const char * const *arg, int *nelems, int *nbytes) |
401 | { |
402 | int i, bytes, count; |
403 | const char * const *a = arg; |
404 | char *p; |
405 | int *q; |
406 | if (arg == 0) { |
407 | *nelems = 0; |
408 | *nbytes = 0; |
409 | return; |
410 | } |
411 | /* count the array elements and number of bytes */ |
412 | for (count=0, bytes=0; *a != 0; count++, a++) { |
413 | bytes += strlen(*a)+1; |
414 | } |
415 | *nbytes = bytes; |
416 | *nelems = count+1; |
417 | } |
418 | |
419 | /* copy the strings from arg[] into buf, starting at given offset |
420 | * return new offset to next free byte |
421 | */ |
422 | static int copystrings(char *buf, int offset, const char * const *arg) { |
423 | char *p; |
424 | const char * const *a; |
425 | int count=0; |
426 | |
427 | if (arg == 0) { |
428 | return offset; |
429 | } |
430 | for (p=buf+offset, a=arg; *a != 0; a++) { |
431 | int len = strlen(*a) +1; |
432 | memcpy(p, *a, len); |
433 | p += len; |
434 | count += len; |
435 | } |
436 | return offset+count; |
437 | } |
438 | |
439 | /** |
440 | * We are unusually paranoid; use of vfork is |
441 | * especially likely to tickle gcc/glibc bugs. |
442 | */ |
443 | #ifdef __attribute_noinline____attribute__ ((__noinline__)) /* See: sys/cdefs.h */ |
444 | __attribute_noinline____attribute__ ((__noinline__)) |
445 | #endif |
446 | |
447 | /* vfork(2) is deprecated on Darwin */ |
448 | #ifndef __APPLE__ |
449 | static pid_t |
450 | vforkChild(ChildStuff *c) { |
451 | volatile pid_t resultPid; |
452 | |
453 | /* |
454 | * We separate the call to vfork into a separate function to make |
455 | * very sure to keep stack of child from corrupting stack of parent, |
456 | * as suggested by the scary gcc warning: |
457 | * warning: variable 'foo' might be clobbered by 'longjmp' or 'vfork' |
458 | */ |
459 | resultPid = vfork(); |
Call to function 'vfork' is insecure as it can lead to denial of service situations in the parent process. Replace calls to vfork with calls to the safer 'posix_spawn' function | |
460 | |
461 | if (resultPid == 0) { |
462 | childProcess(c); |
463 | } |
464 | assert(resultPid != 0)((resultPid != 0) ? (void) (0) : __assert_fail ("resultPid != 0" , "/home/daniel/Projects/java/jdk/src/java.base/unix/native/libjava/ProcessImpl_md.c" , 464, __extension__ __PRETTY_FUNCTION__)); /* childProcess never returns */ |
465 | return resultPid; |
466 | } |
467 | #endif |
468 | |
469 | static pid_t |
470 | forkChild(ChildStuff *c) { |
471 | pid_t resultPid; |
472 | |
473 | /* |
474 | * From Solaris fork(2): In Solaris 10, a call to fork() is |
475 | * identical to a call to fork1(); only the calling thread is |
476 | * replicated in the child process. This is the POSIX-specified |
477 | * behavior for fork(). |
478 | */ |
479 | resultPid = fork(); |
480 | |
481 | if (resultPid == 0) { |
482 | childProcess(c); |
483 | } |
484 | assert(resultPid != 0)((resultPid != 0) ? (void) (0) : __assert_fail ("resultPid != 0" , "/home/daniel/Projects/java/jdk/src/java.base/unix/native/libjava/ProcessImpl_md.c" , 484, __extension__ __PRETTY_FUNCTION__)); /* childProcess never returns */ |
485 | return resultPid; |
486 | } |
487 | |
488 | static pid_t |
489 | spawnChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) { |
490 | pid_t resultPid; |
491 | jboolean isCopy; |
492 | int i, offset, rval, bufsize, magic; |
493 | char *buf, buf1[16]; |
494 | char *hlpargs[2]; |
495 | SpawnInfo sp; |
496 | |
497 | /* need to tell helper which fd is for receiving the childstuff |
498 | * and which fd to send response back on |
499 | */ |
500 | snprintf(buf1, sizeof(buf1), "%d:%d", c->childenv[0], c->fail[1])__builtin___snprintf_chk (buf1, sizeof(buf1), 2 - 1, __builtin_object_size (buf1, 2 > 1), "%d:%d", c->childenv[0], c->fail[1]); |
501 | /* put the fd string as argument to the helper cmd */ |
502 | hlpargs[0] = buf1; |
503 | hlpargs[1] = 0; |
504 | |
505 | /* Following items are sent down the pipe to the helper |
506 | * after it is spawned. |
507 | * All strings are null terminated. All arrays of strings |
508 | * have an empty string for termination. |
509 | * - the ChildStuff struct |
510 | * - the SpawnInfo struct |
511 | * - the argv strings array |
512 | * - the envv strings array |
513 | * - the home directory string |
514 | * - the parentPath string |
515 | * - the parentPathv array |
516 | */ |
517 | /* First calculate the sizes */ |
518 | arraysize(c->argv, &sp.nargv, &sp.argvBytes); |
519 | bufsize = sp.argvBytes; |
520 | arraysize(c->envv, &sp.nenvv, &sp.envvBytes); |
521 | bufsize += sp.envvBytes; |
522 | sp.dirlen = c->pdir == 0 ? 0 : strlen(c->pdir)+1; |
523 | bufsize += sp.dirlen; |
524 | arraysize(parentPathv, &sp.nparentPathv, &sp.parentPathvBytes); |
525 | bufsize += sp.parentPathvBytes; |
526 | /* We need to clear FD_CLOEXEC if set in the fds[]. |
527 | * Files are created FD_CLOEXEC in Java. |
528 | * Otherwise, they will be closed when the target gets exec'd */ |
529 | for (i=0; i<3; i++) { |
530 | if (c->fds[i] != -1) { |
531 | int flags = fcntl(c->fds[i], F_GETFD1); |
532 | if (flags & FD_CLOEXEC1) { |
533 | fcntl(c->fds[i], F_SETFD2, flags & (~1)); |
534 | } |
535 | } |
536 | } |
537 | |
538 | rval = posix_spawn(&resultPid, helperpath, 0, 0, (char * const *) hlpargs, environ); |
539 | |
540 | if (rval != 0) { |
541 | return -1; |
542 | } |
543 | |
544 | /* now the lengths are known, copy the data */ |
545 | buf = NEW(char, bufsize)((char *) xmalloc(env, (bufsize) * sizeof(char))); |
546 | if (buf == 0) { |
547 | return -1; |
548 | } |
549 | offset = copystrings(buf, 0, &c->argv[0]); |
550 | offset = copystrings(buf, offset, &c->envv[0]); |
551 | memcpy(buf+offset, c->pdir, sp.dirlen); |
552 | offset += sp.dirlen; |
553 | offset = copystrings(buf, offset, parentPathv); |
554 | assert(offset == bufsize)((offset == bufsize) ? (void) (0) : __assert_fail ("offset == bufsize" , "/home/daniel/Projects/java/jdk/src/java.base/unix/native/libjava/ProcessImpl_md.c" , 554, __extension__ __PRETTY_FUNCTION__)); |
555 | |
556 | magic = magicNumber(); |
557 | |
558 | /* write the two structs and the data buffer */ |
559 | write(c->childenv[1], (char *)&magic, sizeof(magic)); // magic number first |
560 | write(c->childenv[1], (char *)c, sizeof(*c)); |
561 | write(c->childenv[1], (char *)&sp, sizeof(sp)); |
562 | write(c->childenv[1], buf, bufsize); |
563 | free(buf); |
564 | |
565 | /* In this mode an external main() in invoked which calls back into |
566 | * childProcess() in this file, rather than directly |
567 | * via the statement below */ |
568 | return resultPid; |
569 | } |
570 | |
571 | /* |
572 | * Start a child process running function childProcess. |
573 | * This function only returns in the parent. |
574 | */ |
575 | static pid_t |
576 | startChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) { |
577 | switch (c->mode) { |
578 | /* vfork(2) is deprecated on Darwin*/ |
579 | #ifndef __APPLE__ |
580 | case MODE_VFORK3: |
581 | return vforkChild(c); |
582 | #endif |
583 | case MODE_FORK1: |
584 | return forkChild(c); |
585 | case MODE_POSIX_SPAWN2: |
586 | return spawnChild(env, process, c, helperpath); |
587 | default: |
588 | return -1; |
589 | } |
590 | } |
591 | |
592 | JNIEXPORT__attribute__((visibility("default"))) jint JNICALL |
593 | Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env, |
594 | jobject process, |
595 | jint mode, |
596 | jbyteArray helperpath, |
597 | jbyteArray prog, |
598 | jbyteArray argBlock, jint argc, |
599 | jbyteArray envBlock, jint envc, |
600 | jbyteArray dir, |
601 | jintArray std_fds, |
602 | jboolean redirectErrorStream) |
603 | { |
604 | int errnum; |
605 | int resultPid = -1; |
606 | int in[2], out[2], err[2], fail[2], childenv[2]; |
607 | jint *fds = NULL((void*)0); |
608 | const char *phelperpath = NULL((void*)0); |
609 | const char *pprog = NULL((void*)0); |
610 | const char *pargBlock = NULL((void*)0); |
611 | const char *penvBlock = NULL((void*)0); |
612 | ChildStuff *c; |
613 | |
614 | in[0] = in[1] = out[0] = out[1] = err[0] = err[1] = fail[0] = fail[1] = -1; |
615 | childenv[0] = childenv[1] = -1; |
616 | |
617 | if ((c = NEW(ChildStuff, 1)((ChildStuff *) xmalloc(env, (1) * sizeof(ChildStuff)))) == NULL((void*)0)) return -1; |
618 | c->argv = NULL((void*)0); |
619 | c->envv = NULL((void*)0); |
620 | c->pdir = NULL((void*)0); |
621 | |
622 | /* Convert prog + argBlock into a char ** argv. |
623 | * Add one word room for expansion of argv for use by |
624 | * execve_as_traditional_shell_script. |
625 | * This word is also used when using posix_spawn mode |
626 | */ |
627 | assert(prog != NULL && argBlock != NULL)((prog != ((void*)0) && argBlock != ((void*)0)) ? (void ) (0) : __assert_fail ("prog != NULL && argBlock != NULL" , "/home/daniel/Projects/java/jdk/src/java.base/unix/native/libjava/ProcessImpl_md.c" , 627, __extension__ __PRETTY_FUNCTION__)); |
628 | if ((phelperpath = getBytes(env, helperpath)) == NULL((void*)0)) goto Catch; |
629 | if ((pprog = getBytes(env, prog)) == NULL((void*)0)) goto Catch; |
630 | if ((pargBlock = getBytes(env, argBlock)) == NULL((void*)0)) goto Catch; |
631 | if ((c->argv = NEW(const char *, argc + 3)((const char * *) xmalloc(env, (argc + 3) * sizeof(const char *)))) == NULL((void*)0)) goto Catch; |
632 | c->argv[0] = pprog; |
633 | c->argc = argc + 2; |
634 | initVectorFromBlock(c->argv+1, pargBlock, argc); |
635 | |
636 | if (envBlock != NULL((void*)0)) { |
637 | /* Convert envBlock into a char ** envv */ |
638 | if ((penvBlock = getBytes(env, envBlock)) == NULL((void*)0)) goto Catch; |
639 | if ((c->envv = NEW(const char *, envc + 1)((const char * *) xmalloc(env, (envc + 1) * sizeof(const char *)))) == NULL((void*)0)) goto Catch; |
640 | initVectorFromBlock(c->envv, penvBlock, envc); |
641 | } |
642 | |
643 | if (dir != NULL((void*)0)) { |
644 | if ((c->pdir = getBytes(env, dir)) == NULL((void*)0)) goto Catch; |
645 | } |
646 | |
647 | assert(std_fds != NULL)((std_fds != ((void*)0)) ? (void) (0) : __assert_fail ("std_fds != NULL" , "/home/daniel/Projects/java/jdk/src/java.base/unix/native/libjava/ProcessImpl_md.c" , 647, __extension__ __PRETTY_FUNCTION__)); |
648 | fds = (*env)->GetIntArrayElements(env, std_fds, NULL((void*)0)); |
649 | if (fds == NULL((void*)0)) goto Catch; |
650 | |
651 | if ((fds[0] == -1 && pipe(in) < 0) || |
652 | (fds[1] == -1 && pipe(out) < 0) || |
653 | (fds[2] == -1 && pipe(err) < 0) || |
654 | (pipe(childenv) < 0) || |
655 | (pipe(fail) < 0)) { |
656 | throwIOException(env, errno(*__errno_location ()), "Bad file descriptor"); |
657 | goto Catch; |
658 | } |
659 | c->fds[0] = fds[0]; |
660 | c->fds[1] = fds[1]; |
661 | c->fds[2] = fds[2]; |
662 | |
663 | copyPipe(in, c->in); |
664 | copyPipe(out, c->out); |
665 | copyPipe(err, c->err); |
666 | copyPipe(fail, c->fail); |
667 | copyPipe(childenv, c->childenv); |
668 | |
669 | c->redirectErrorStream = redirectErrorStream; |
670 | c->mode = mode; |
671 | |
672 | /* In posix_spawn mode, require the child process to signal aliveness |
673 | * right after it comes up. This is because there are implementations of |
674 | * posix_spawn() which do not report failed exec()s back to the caller |
675 | * (e.g. glibc, see JDK-8223777). In those cases, the fork() will have |
676 | * worked and successfully started the child process, but the exec() will |
677 | * have failed. There is no way for us to distinguish this from a target |
678 | * binary just exiting right after start. |
679 | * |
680 | * Note that we could do this additional handshake in all modes but for |
681 | * prudence only do it when it is needed (in posix_spawn mode). */ |
682 | c->sendAlivePing = (mode == MODE_POSIX_SPAWN2) ? 1 : 0; |
683 | |
684 | resultPid = startChild(env, process, c, phelperpath); |
685 | assert(resultPid != 0)((resultPid != 0) ? (void) (0) : __assert_fail ("resultPid != 0" , "/home/daniel/Projects/java/jdk/src/java.base/unix/native/libjava/ProcessImpl_md.c" , 685, __extension__ __PRETTY_FUNCTION__)); |
686 | |
687 | if (resultPid < 0) { |
688 | switch (c->mode) { |
689 | case MODE_VFORK3: |
690 | throwIOException(env, errno(*__errno_location ()), "vfork failed"); |
691 | break; |
692 | case MODE_FORK1: |
693 | throwIOException(env, errno(*__errno_location ()), "fork failed"); |
694 | break; |
695 | case MODE_POSIX_SPAWN2: |
696 | throwIOException(env, errno(*__errno_location ()), "posix_spawn failed"); |
697 | break; |
698 | } |
699 | goto Catch; |
700 | } |
701 | close(fail[1]); fail[1] = -1; /* See: WhyCantJohnnyExec (childproc.c) */ |
702 | |
703 | /* If we expect the child to ping aliveness, wait for it. */ |
704 | if (c->sendAlivePing) { |
705 | switch(readFully(fail[0], &errnum, sizeof(errnum))) { |
706 | case 0: /* First exec failed; */ |
707 | { |
708 | int tmpStatus = 0; |
709 | int p = waitpid(resultPid, &tmpStatus, 0); |
710 | throwExitCause(env, p, tmpStatus); |
711 | goto Catch; |
712 | } |
713 | case sizeof(errnum): |
714 | assert(errnum == CHILD_IS_ALIVE)((errnum == 65535) ? (void) (0) : __assert_fail ("errnum == CHILD_IS_ALIVE" , "/home/daniel/Projects/java/jdk/src/java.base/unix/native/libjava/ProcessImpl_md.c" , 714, __extension__ __PRETTY_FUNCTION__)); |
715 | if (errnum != CHILD_IS_ALIVE65535) { |
716 | /* Should never happen since the first thing the spawn |
717 | * helper should do is to send an alive ping to the parent, |
718 | * before doing any subsequent work. */ |
719 | throwIOException(env, 0, "Bad code from spawn helper " |
720 | "(Failed to exec spawn helper)"); |
721 | goto Catch; |
722 | } |
723 | break; |
724 | default: |
725 | throwIOException(env, errno(*__errno_location ()), "Read failed"); |
726 | goto Catch; |
727 | } |
728 | } |
729 | |
730 | switch (readFully(fail[0], &errnum, sizeof(errnum))) { |
731 | case 0: break; /* Exec succeeded */ |
732 | case sizeof(errnum): |
733 | waitpid(resultPid, NULL((void*)0), 0); |
734 | throwIOException(env, errnum, "Exec failed"); |
735 | goto Catch; |
736 | default: |
737 | throwIOException(env, errno(*__errno_location ()), "Read failed"); |
738 | goto Catch; |
739 | } |
740 | |
741 | fds[0] = (in [1] != -1) ? in [1] : -1; |
742 | fds[1] = (out[0] != -1) ? out[0] : -1; |
743 | fds[2] = (err[0] != -1) ? err[0] : -1; |
744 | |
745 | Finally: |
746 | /* Always clean up the child's side of the pipes */ |
747 | closeSafely(in [0]); |
748 | closeSafely(out[1]); |
749 | closeSafely(err[1]); |
750 | |
751 | /* Always clean up fail and childEnv descriptors */ |
752 | closeSafely(fail[0]); |
753 | closeSafely(fail[1]); |
754 | closeSafely(childenv[0]); |
755 | closeSafely(childenv[1]); |
756 | |
757 | releaseBytes(env, helperpath, phelperpath); |
758 | releaseBytes(env, prog, pprog); |
759 | releaseBytes(env, argBlock, pargBlock); |
760 | releaseBytes(env, envBlock, penvBlock); |
761 | releaseBytes(env, dir, c->pdir); |
762 | |
763 | free(c->argv); |
764 | free(c->envv); |
765 | free(c); |
766 | |
767 | if (fds != NULL((void*)0)) |
768 | (*env)->ReleaseIntArrayElements(env, std_fds, fds, 0); |
769 | |
770 | return resultPid; |
771 | |
772 | Catch: |
773 | /* Clean up the parent's side of the pipes in case of failure only */ |
774 | closeSafely(in [1]); in[1] = -1; |
775 | closeSafely(out[0]); out[0] = -1; |
776 | closeSafely(err[0]); err[0] = -1; |
777 | goto Finally; |
778 | } |
779 |