Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ProcessImpl_md.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mthread-model posix -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-10/lib/clang/10.0.0 -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/modules_include/java.base -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/modules_include/java.base/linux -I /home/daniel/Projects/java/jdk/src/java.base/share/native/libjava -I /home/daniel/Projects/java/jdk/src/java.base/unix/native/libjava -I /home/daniel/Projects/java/jdk/src/hotspot/share/include -I /home/daniel/Projects/java/jdk/src/hotspot/os/posix/include -D LIBC=gnu -D _GNU_SOURCE -D _REENTRANT -D _LARGEFILE64_SOURCE -D LINUX -D DEBUG -D _LITTLE_ENDIAN -D ARCH="amd64" -D amd64 -D _LP64=1 -D ARCHPROPNAME="amd64" -I /home/daniel/Projects/java/jdk/src/java.base/linux/native/libjava -I /home/daniel/Projects/java/jdk/src/java.base/unix/native/libjava -I /home/daniel/Projects/java/jdk/src/java.base/share/native/libjava -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/headers/java.base -I /home/daniel/Projects/java/jdk/src/java.base/share/native/libfdlibm -D _FORTIFY_SOURCE=2 -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-10/lib/clang/10.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-unused -Wno-unused-result -Wno-unused-function -std=c99 -fdebug-compilation-dir /home/daniel/Projects/java/jdk/make -ferror-limit 19 -fmessage-length 0 -fvisibility hidden -stack-protector 1 -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o /home/daniel/Projects/java/scan/2021-12-21-193737-8510-1 -x c /home/daniel/Projects/java/jdk/src/java.base/unix/native/libjava/ProcessImpl_md.c
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
185static void
186setSIGCHLDHandler(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
214static void*
215xmalloc(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 */
230static const char*
231defaultPath(void)
232{
233 return ":/bin:/usr/bin";
234}
235
236static const char*
237effectivePath(void)
238{
239 const char *s = getenv("PATH");
240 return (s != NULL((void*)0)) ? s : defaultPath();
241}
242
243static int
244countOccurrences(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
252static const char * const *
253effectivePathv(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
278JNIEXPORT__attribute__((visibility("default"))) void JNICALL
279Java_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
303static const char *
304getBytes(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
310static void
311releaseBytes(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
319static void
320throwIOException(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 */
353static 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? */
373static void
374debugPrint(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
385static void
386copyPipe(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 */
400static 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 */
422static 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__
449static pid_t
450vforkChild(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
469static pid_t
470forkChild(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
488static pid_t
489spawnChild(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 */
575static pid_t
576startChild(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
592JNIEXPORT__attribute__((visibility("default"))) jint JNICALL
593Java_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