< prev index next >

src/java.base/unix/native/libjava/ProcessImpl_md.c

Print this page




 308 #define WTERMSIG(status) ((status)&0x7F)
 309 #endif
 310 
 311 static const char *
 312 getBytes(JNIEnv *env, jbyteArray arr)
 313 {
 314     return arr == NULL ? NULL :
 315         (const char*) (*env)->GetByteArrayElements(env, arr, NULL);
 316 }
 317 
 318 static void
 319 releaseBytes(JNIEnv *env, jbyteArray arr, const char* parr)
 320 {
 321     if (parr != NULL)
 322         (*env)->ReleaseByteArrayElements(env, arr, (jbyte*) parr, JNI_ABORT);
 323 }
 324 
 325 #define IOE_FORMAT "error=%d, %s"
 326 
 327 static void
 328 throwIOException(JNIEnv *env, int errnum, const char *defaultDetail)
 329 {
 330     const char *detail = defaultDetail;
 331     char *errmsg;
 332     size_t fmtsize;
 333     char tmpbuf[1024];
 334     jstring s;
 335 
 336     if (errnum != 0) {
 337         int ret = getErrorString(errnum, tmpbuf, sizeof(tmpbuf));
 338         if (ret != EINVAL)
 339             detail = tmpbuf;
 340     }
 341     /* ASCII Decimal representation uses 2.4 times as many bits as binary. */
 342     fmtsize = sizeof(IOE_FORMAT) + strlen(detail) + 3 * sizeof(errnum);

 343     errmsg = NEW(char, fmtsize);
 344     if (errmsg == NULL)
 345         return;
 346 
 347     snprintf(errmsg, fmtsize, IOE_FORMAT, errnum, detail);






 348     s = JNU_NewStringPlatform(env, errmsg);
 349     if (s != NULL) {
 350         jobject x = JNU_NewObjectByName(env, "java/io/IOException",
 351                                         "(Ljava/lang/String;)V", s);
 352         if (x != NULL)
 353             (*env)->Throw(env, x);
 354     }
 355     free(errmsg);
 356 }
 357 
 358 #ifdef DEBUG_PROCESS
 359 /* Debugging process code is difficult; where to write debug output? */
 360 static void
 361 debugPrint(char *format, ...)
 362 {
 363     FILE *tty = fopen("/dev/tty", "w");
 364     va_list ap;
 365     va_start(ap, format);
 366     vfprintf(tty, format, ap);
 367     va_end(ap);


 455 
 456 static pid_t
 457 forkChild(ChildStuff *c) {
 458     pid_t resultPid;
 459 
 460     /*
 461      * From Solaris fork(2): In Solaris 10, a call to fork() is
 462      * identical to a call to fork1(); only the calling thread is
 463      * replicated in the child process. This is the POSIX-specified
 464      * behavior for fork().
 465      */
 466     resultPid = fork();
 467 
 468     if (resultPid == 0) {
 469         childProcess(c);
 470     }
 471     assert(resultPid != 0);  /* childProcess never returns */
 472     return resultPid;
 473 }
 474 
 475 /* Returns 1 if spawnhelper executable bits are set as expected. */
 476 static int check_helper(const char* helperpath) {


















 477     struct stat s;
 478     int rc = stat(helperpath, &s);
 479     if (rc == 0) {
 480         /* Require all bits set since this is how jspawnhelper
 481          * is set up in a canonical installation */
 482         if (s.st_mode & S_IXUSR &&
 483             s.st_mode & S_IXGRP &&
 484             s.st_mode & S_IXOTH) {
 485             return 1;
 486         } else {
 487             return 0;
 488         }
 489     } else {
 490         return 0;
 491     }


 492 }
 493 
 494 static pid_t
 495 spawnChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) {
 496     pid_t resultPid;
 497     jboolean isCopy;
 498     int i, offset, rval, bufsize, magic;
 499     char *buf, buf1[16];
 500     char *hlpargs[2];
 501     SpawnInfo sp;
 502 
 503     /* Some posix_spawn() implementations do not report exec() errors back to the caller;
 504      * POSIX leaves that up to the implementor, it only requires the child process to fail with
 505      * error code 127.
 506      * Since we cannot use that information (the payload binary may also use exit code 127 for
 507      * its own purposes), lets do at least a basic guess if exec(jspawnhelper) will succeed.
 508      * There are many reasons why it could fail, most of which one cannot be tested without
 509      * exec'ing, but we can at least check permissions. Since jspawnhelper is part of the JDK
 510      * it should have the execute permissions set correctly. */
 511     if (check_helper(helperpath) == 0) {
 512         throwIOException(env, 0, "jspawnhelper is not accessible.");



 513         return -1;
 514     }
 515 
 516     /* need to tell helper which fd is for receiving the childstuff
 517      * and which fd to send response back on
 518      */
 519     snprintf(buf1, sizeof(buf1), "%d:%d", c->childenv[0], c->fail[1]);
 520     /* put the fd string as argument to the helper cmd */
 521     hlpargs[0] = buf1;
 522     hlpargs[1] = 0;
 523 
 524     /* Following items are sent down the pipe to the helper
 525      * after it is spawned.
 526      * All strings are null terminated. All arrays of strings
 527      * have an empty string for termination.
 528      * - the ChildStuff struct
 529      * - the SpawnInfo struct
 530      * - the argv strings array
 531      * - the envv strings array
 532      * - the home directory string


 655     if (envBlock != NULL) {
 656         /* Convert envBlock into a char ** envv */
 657         if ((penvBlock = getBytes(env, envBlock))   == NULL) goto Catch;
 658         if ((c->envv = NEW(const char *, envc + 1)) == NULL) goto Catch;
 659         initVectorFromBlock(c->envv, penvBlock, envc);
 660     }
 661 
 662     if (dir != NULL) {
 663         if ((c->pdir = getBytes(env, dir)) == NULL) goto Catch;
 664     }
 665 
 666     assert(std_fds != NULL);
 667     fds = (*env)->GetIntArrayElements(env, std_fds, NULL);
 668     if (fds == NULL) goto Catch;
 669 
 670     if ((fds[0] == -1 && pipe(in)  < 0) ||
 671         (fds[1] == -1 && pipe(out) < 0) ||
 672         (fds[2] == -1 && pipe(err) < 0) ||
 673         (pipe(childenv) < 0) ||
 674         (pipe(fail) < 0)) {
 675         throwIOException(env, errno, "Bad file descriptor");
 676         goto Catch;
 677     }
 678     c->fds[0] = fds[0];
 679     c->fds[1] = fds[1];
 680     c->fds[2] = fds[2];
 681 
 682     copyPipe(in,   c->in);
 683     copyPipe(out,  c->out);
 684     copyPipe(err,  c->err);
 685     copyPipe(fail, c->fail);
 686     copyPipe(childenv, c->childenv);
 687 
 688     c->redirectErrorStream = redirectErrorStream;
 689     c->mode = mode;

 690 
 691     resultPid = startChild(env, process, c, phelperpath);
 692     assert(resultPid != 0);
 693 
 694     if (resultPid < 0) {
 695         /* Throw an IOException with a generic text unless an exception was already raised. */
 696         if (!(*env)->ExceptionCheck(env)) {
 697             switch (c->mode) {
 698               case MODE_VFORK:
 699                 throwIOException(env, errno, "vfork failed");
 700                 break;
 701               case MODE_FORK:
 702                 throwIOException(env, errno, "fork failed");
 703                 break;
 704               case MODE_POSIX_SPAWN:
 705                 throwIOException(env, errno, "posix_spawn failed");
 706                 break;
 707             }
 708         }
 709         goto Catch;
 710     }
 711     close(fail[1]); fail[1] = -1; /* See: WhyCantJohnnyExec  (childproc.c)  */
 712 
 713     switch (readFully(fail[0], &errnum, sizeof(errnum))) {
 714     case 0: break; /* Exec succeeded */
 715     case sizeof(errnum):
 716         waitpid(resultPid, NULL, 0);
 717         throwIOException(env, errnum, "Exec failed");
 718         goto Catch;
 719     default:
 720         throwIOException(env, errno, "Read failed");
 721         goto Catch;
 722     }
 723 
 724     fds[0] = (in [1] != -1) ? in [1] : -1;
 725     fds[1] = (out[0] != -1) ? out[0] : -1;
 726     fds[2] = (err[0] != -1) ? err[0] : -1;
 727 
 728  Finally:
 729     /* Always clean up the child's side of the pipes */
 730     closeSafely(in [0]);
 731     closeSafely(out[1]);
 732     closeSafely(err[1]);
 733 
 734     /* Always clean up fail and childEnv descriptors */
 735     closeSafely(fail[0]);
 736     closeSafely(fail[1]);
 737     closeSafely(childenv[0]);
 738     closeSafely(childenv[1]);
 739 
 740     releaseBytes(env, helperpath, phelperpath);




 308 #define WTERMSIG(status) ((status)&0x7F)
 309 #endif
 310 
 311 static const char *
 312 getBytes(JNIEnv *env, jbyteArray arr)
 313 {
 314     return arr == NULL ? NULL :
 315         (const char*) (*env)->GetByteArrayElements(env, arr, NULL);
 316 }
 317 
 318 static void
 319 releaseBytes(JNIEnv *env, jbyteArray arr, const char* parr)
 320 {
 321     if (parr != NULL)
 322         (*env)->ReleaseByteArrayElements(env, arr, (jbyte*) parr, JNI_ABORT);
 323 }
 324 
 325 #define IOE_FORMAT "error=%d, %s"
 326 
 327 static void
 328 throwIOException(JNIEnv *env, int errnum, const char *defaultDetail, const char* addinfo)
 329 {
 330     const char *detail = defaultDetail;
 331     char *errmsg;
 332     size_t fmtsize;
 333     char tmpbuf[1024];
 334     jstring s;
 335 
 336     if (errnum != 0) {
 337         int ret = getErrorString(errnum, tmpbuf, sizeof(tmpbuf));
 338         if (ret != EINVAL)
 339             detail = tmpbuf;
 340     }
 341     /* ASCII Decimal representation uses 2.4 times as many bits as binary. */
 342     fmtsize = sizeof(IOE_FORMAT) + strlen(detail) + 3 * sizeof(errnum) +
 343               (addinfo == NULL ? 0 : 1 + strlen(addinfo) + 2); // " (<info>)"
 344     errmsg = NEW(char, fmtsize);
 345     if (errmsg == NULL)
 346         return;
 347 
 348     snprintf(errmsg, fmtsize, IOE_FORMAT, errnum, detail);
 349     if (addinfo != NULL) {
 350       strcat(errmsg, " (");
 351       strcat(errmsg, addinfo);
 352       strcat(errmsg, ")");
 353     }
 354 
 355     s = JNU_NewStringPlatform(env, errmsg);
 356     if (s != NULL) {
 357         jobject x = JNU_NewObjectByName(env, "java/io/IOException",
 358                                         "(Ljava/lang/String;)V", s);
 359         if (x != NULL)
 360             (*env)->Throw(env, x);
 361     }
 362     free(errmsg);
 363 }
 364 
 365 #ifdef DEBUG_PROCESS
 366 /* Debugging process code is difficult; where to write debug output? */
 367 static void
 368 debugPrint(char *format, ...)
 369 {
 370     FILE *tty = fopen("/dev/tty", "w");
 371     va_list ap;
 372     va_start(ap, format);
 373     vfprintf(tty, format, ap);
 374     va_end(ap);


 462 
 463 static pid_t
 464 forkChild(ChildStuff *c) {
 465     pid_t resultPid;
 466 
 467     /*
 468      * From Solaris fork(2): In Solaris 10, a call to fork() is
 469      * identical to a call to fork1(); only the calling thread is
 470      * replicated in the child process. This is the POSIX-specified
 471      * behavior for fork().
 472      */
 473     resultPid = fork();
 474 
 475     if (resultPid == 0) {
 476         childProcess(c);
 477     }
 478     assert(resultPid != 0);  /* childProcess never returns */
 479     return resultPid;
 480 }
 481 
 482 /* Returns 0 if at least one executable bit is set on the spawn helper binary,
 483  * -1 otherwise. */
 484 static int isHelperExecutable(const char* helperpath) {
 485     /* Note that this check will never be sufficient; exec() may still fail
 486      * for many reasons and it is impossible to predict them all. The point of
 487      * this test is to catch the most common failure reason and give the caller
 488      * a clear diagnostic message.
 489      * But never shall this test give us false positives (make us avoid exec()ing
 490      * where it would have actually worked.) So since exec() success cannot be
 491      * completely predicted, we err on the side of false negatives - when in doubt,
 492      * try it.
 493      */
 494     static int cached_rc = -2;
 495     if (cached_rc == 0 || cached_rc == -1) {
 496         /* The helper binary is part of the JDK and should have been set up
 497          * correctly. This is very unlikely to happen intermittently. Therefore
 498          * it should be okay to cache the result. */
 499         return cached_rc;
 500     }
 501 
 502     struct stat s;
 503     int rc = stat(helperpath, &s);
 504     if (rc == 0) {
 505         /* Require at least one exec bit set since this is how the spawn helper
 506          * is set up in a canonical installation. */
 507         if (s.st_mode & S_IXUSR ||
 508             s.st_mode & S_IXGRP ||
 509             s.st_mode & S_IXOTH) {
 510             cached_rc = 0;

 511             return 0;
 512         }


 513     }
 514     cached_rc = -1;
 515     return -1;
 516 }
 517 
 518 static pid_t
 519 spawnChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) {
 520     pid_t resultPid = -1;
 521     jboolean isCopy;
 522     int i, offset, rval, bufsize, magic;
 523     char *buf, buf1[16];
 524     char *hlpargs[2];
 525     SpawnInfo sp;
 526 
 527     /* Some posix_spawn() implementations do not report exec() errors back to the caller;
 528      * POSIX leaves that up to the implementor, it only requires the child process to fail with
 529      * error code 127.
 530      * The problem with that is that posix_spawn() will seemingly succeed, child process will
 531      * have been started but will immediately die with exit code 127. This is impossible to
 532      * tell apart from cases where we successfully exec()'d the target program and it died
 533      * with 127. In the former case we want to throw an IOException, the latter case is fine
 534      * and should be handled by the java program.
 535      * There is no perfect solution, but here we try - before starting the child - to catch
 536      * obvious cases which will make the first exec() fail. */
 537     if (isHelperExecutable(helperpath) != 0) {
 538         errno = EACCES;
 539         c->error_detail = "No execute permission for spawn helper.";
 540         return -1;
 541     }
 542 
 543     /* need to tell helper which fd is for receiving the childstuff
 544      * and which fd to send response back on
 545      */
 546     snprintf(buf1, sizeof(buf1), "%d:%d", c->childenv[0], c->fail[1]);
 547     /* put the fd string as argument to the helper cmd */
 548     hlpargs[0] = buf1;
 549     hlpargs[1] = 0;
 550 
 551     /* Following items are sent down the pipe to the helper
 552      * after it is spawned.
 553      * All strings are null terminated. All arrays of strings
 554      * have an empty string for termination.
 555      * - the ChildStuff struct
 556      * - the SpawnInfo struct
 557      * - the argv strings array
 558      * - the envv strings array
 559      * - the home directory string


 682     if (envBlock != NULL) {
 683         /* Convert envBlock into a char ** envv */
 684         if ((penvBlock = getBytes(env, envBlock))   == NULL) goto Catch;
 685         if ((c->envv = NEW(const char *, envc + 1)) == NULL) goto Catch;
 686         initVectorFromBlock(c->envv, penvBlock, envc);
 687     }
 688 
 689     if (dir != NULL) {
 690         if ((c->pdir = getBytes(env, dir)) == NULL) goto Catch;
 691     }
 692 
 693     assert(std_fds != NULL);
 694     fds = (*env)->GetIntArrayElements(env, std_fds, NULL);
 695     if (fds == NULL) goto Catch;
 696 
 697     if ((fds[0] == -1 && pipe(in)  < 0) ||
 698         (fds[1] == -1 && pipe(out) < 0) ||
 699         (fds[2] == -1 && pipe(err) < 0) ||
 700         (pipe(childenv) < 0) ||
 701         (pipe(fail) < 0)) {
 702         throwIOException(env, errno, "Bad file descriptor", NULL);
 703         goto Catch;
 704     }
 705     c->fds[0] = fds[0];
 706     c->fds[1] = fds[1];
 707     c->fds[2] = fds[2];
 708 
 709     copyPipe(in,   c->in);
 710     copyPipe(out,  c->out);
 711     copyPipe(err,  c->err);
 712     copyPipe(fail, c->fail);
 713     copyPipe(childenv, c->childenv);
 714 
 715     c->redirectErrorStream = redirectErrorStream;
 716     c->mode = mode;
 717     c->error_detail = NULL;
 718 
 719     resultPid = startChild(env, process, c, phelperpath);
 720     assert(resultPid != 0);
 721 
 722     if (resultPid < 0) {


 723         switch (c->mode) {
 724           case MODE_VFORK:
 725             throwIOException(env, errno, "vfork failed", c->error_detail);
 726             break;
 727           case MODE_FORK:
 728             throwIOException(env, errno, "fork failed", c->error_detail);
 729             break;
 730           case MODE_POSIX_SPAWN:
 731             throwIOException(env, errno, "posix_spawn failed", c->error_detail);
 732             break;
 733         }

 734         goto Catch;
 735     }
 736     close(fail[1]); fail[1] = -1; /* See: WhyCantJohnnyExec  (childproc.c)  */
 737 
 738     switch (readFully(fail[0], &errnum, sizeof(errnum))) {
 739     case 0: break; /* Exec succeeded */
 740     case sizeof(errnum):
 741         waitpid(resultPid, NULL, 0);
 742         throwIOException(env, errnum, "Exec failed", NULL);
 743         goto Catch;
 744     default:
 745         throwIOException(env, errno, "Read failed", NULL);
 746         goto Catch;
 747     }
 748 
 749     fds[0] = (in [1] != -1) ? in [1] : -1;
 750     fds[1] = (out[0] != -1) ? out[0] : -1;
 751     fds[2] = (err[0] != -1) ? err[0] : -1;
 752 
 753  Finally:
 754     /* Always clean up the child's side of the pipes */
 755     closeSafely(in [0]);
 756     closeSafely(out[1]);
 757     closeSafely(err[1]);
 758 
 759     /* Always clean up fail and childEnv descriptors */
 760     closeSafely(fail[0]);
 761     closeSafely(fail[1]);
 762     closeSafely(childenv[0]);
 763     closeSafely(childenv[1]);
 764 
 765     releaseBytes(env, helperpath, phelperpath);


< prev index next >