104 * the exec of the specified launcher version. |
108 * the exec of the specified launcher version. |
105 * |
109 * |
106 * Previously the launcher modified the LD_LIBRARY_PATH appropriately for the |
110 * Previously the launcher modified the LD_LIBRARY_PATH appropriately for the |
107 * desired data model path, regardless if data models matched or not. The |
111 * desired data model path, regardless if data models matched or not. The |
108 * launcher subsequently exec'ed the desired executable, in order to make the |
112 * launcher subsequently exec'ed the desired executable, in order to make the |
109 * LD_LIBRARY_PATH path available for the runtime linker. This is no longer the |
113 * LD_LIBRARY_PATH path available, for the runtime linker. |
110 * case, the launcher dlopens the target libjvm.so. All other required |
114 * |
111 * libraries are loaded by the runtime linker, by virtue of the $ORIGIN paths |
115 * Now, in most cases,the launcher will dlopen the target libjvm.so. All |
112 * baked into the shared libraries, by the build infrastructure at compile time. |
116 * required libraries are loaded by the runtime linker, using the |
|
117 * $RPATH/$ORIGIN baked into the shared libraries at compile time. Therefore, |
|
118 * in most cases, the launcher will only exec, if the data models are |
|
119 * mismatched, and will not set any environment variables, regardless of the |
|
120 * data models. |
|
121 * |
|
122 * However, if the environment contains a LD_LIBRARY_PATH, this will cause the |
|
123 * launcher to inspect the LD_LIBRARY_PATH. The launcher will check |
|
124 * a. if the LD_LIBRARY_PATH's first component is the the path to the desired |
|
125 * libjvm.so |
|
126 * b. if any other libjvm.so is found in any of the paths. |
|
127 * If case b is true, then the launcher will set the LD_LIBRARY_PATH to the |
|
128 * desired JRE and reexec, in order to propagate the environment. |
113 * |
129 * |
114 * Main |
130 * Main |
115 * (incoming argv) |
131 * (incoming argv) |
116 * | |
132 * | |
117 * \|/ |
133 * \|/ |
179 #endif /* DUAL_MODE */ |
230 #endif /* DUAL_MODE */ |
180 default: |
231 default: |
181 return LIBARCHNAME; |
232 return LIBARCHNAME; |
182 } |
233 } |
183 } |
234 } |
|
235 |
|
236 #ifdef SETENV_REQUIRED |
|
237 static jboolean |
|
238 JvmExists(const char *path) { |
|
239 char tmp[PATH_MAX + 1]; |
|
240 struct stat statbuf; |
|
241 JLI_Snprintf(tmp, PATH_MAX, "%s/%s", path, JVM_DLL); |
|
242 if (stat(tmp, &statbuf) == 0) { |
|
243 return JNI_TRUE; |
|
244 } |
|
245 return JNI_FALSE; |
|
246 } |
|
247 /* |
|
248 * contains a lib/$LIBARCH/{server,client}/libjvm.so ? |
|
249 */ |
|
250 static jboolean |
|
251 ContainsLibJVM(int wanted, const char *env) { |
|
252 char clientPattern[PATH_MAX + 1]; |
|
253 char serverPattern[PATH_MAX + 1]; |
|
254 char *envpath; |
|
255 char *path; |
|
256 jboolean clientPatternFound; |
|
257 jboolean serverPatternFound; |
|
258 |
|
259 /* fastest path */ |
|
260 if (env == NULL) { |
|
261 return JNI_FALSE; |
|
262 } |
|
263 |
|
264 /* the usual suspects */ |
|
265 JLI_Snprintf(clientPattern, PATH_MAX, "lib/%s/client", GetArchPath(wanted)); |
|
266 JLI_Snprintf(serverPattern, PATH_MAX, "lib/%s/server", GetArchPath(wanted)); |
|
267 |
|
268 /* to optimize for time, test if any of our usual suspects are present. */ |
|
269 clientPatternFound = JLI_StrStr(env, clientPattern) != NULL; |
|
270 serverPatternFound = JLI_StrStr(env, serverPattern) != NULL; |
|
271 if (clientPatternFound == JNI_FALSE && serverPatternFound == JNI_FALSE) { |
|
272 return JNI_FALSE; |
|
273 } |
|
274 |
|
275 /* |
|
276 * we have a suspicious path component, check if it contains a libjvm.so |
|
277 */ |
|
278 envpath = JLI_StringDup(env); |
|
279 for (path = JLI_StrTok(envpath, ":"); path != NULL; path = JLI_StrTok(NULL, ":")) { |
|
280 if (clientPatternFound && JLI_StrStr(path, clientPattern) != NULL) { |
|
281 if (JvmExists(path)) { |
|
282 JLI_MemFree(envpath); |
|
283 return JNI_TRUE; |
|
284 } |
|
285 } |
|
286 if (serverPatternFound && JLI_StrStr(path, serverPattern) != NULL) { |
|
287 if (JvmExists(path)) { |
|
288 JLI_MemFree(envpath); |
|
289 return JNI_TRUE; |
|
290 } |
|
291 } |
|
292 } |
|
293 JLI_MemFree(envpath); |
|
294 return JNI_FALSE; |
|
295 } |
|
296 |
|
297 /* |
|
298 * Test whether the environment variable needs to be set, see flowchart. |
|
299 */ |
|
300 static jboolean |
|
301 RequiresSetenv(int wanted, const char *jvmpath) { |
|
302 char jpath[PATH_MAX + 1]; |
|
303 char *llp; |
|
304 char *dmllp = NULL; |
|
305 char *p; /* a utility pointer */ |
|
306 |
|
307 llp = getenv("LD_LIBRARY_PATH"); |
|
308 #ifdef __solaris__ |
|
309 dmllp = (CURRENT_DATA_MODEL == 32) |
|
310 ? getenv("LD_LIBRARY_PATH_32") |
|
311 : getenv("LD_LIBRARY_PATH_64"); |
|
312 #endif /* __solaris__ */ |
|
313 /* no environment variable is a good environment variable */ |
|
314 if (llp == NULL && dmllp == NULL) { |
|
315 return JNI_FALSE; |
|
316 } |
|
317 #ifdef __linux |
|
318 /* |
|
319 * On linux, if a binary is running as sgid or suid, glibc sets |
|
320 * LD_LIBRARY_PATH to the empty string for security purposes. (In contrast, |
|
321 * on Solaris the LD_LIBRARY_PATH variable for a privileged binary does not |
|
322 * lose its settings; but the dynamic linker does apply more scrutiny to the |
|
323 * path.) The launcher uses the value of LD_LIBRARY_PATH to prevent an exec |
|
324 * loop, here and further downstream. Therefore, if we are running sgid or |
|
325 * suid, this function's setting of LD_LIBRARY_PATH will be ineffective and |
|
326 * we should case a return from the calling function. Getting the right |
|
327 * libraries will be handled by the RPATH. In reality, this check is |
|
328 * redundant, as the previous check for a non-null LD_LIBRARY_PATH will |
|
329 * return back to the calling function forthwith, it is left here to safe |
|
330 * guard against any changes, in the glibc's existing security policy. |
|
331 */ |
|
332 if ((getgid() != getegid()) || (getuid() != geteuid())) { |
|
333 return JNI_FALSE; |
|
334 } |
|
335 #endif /* __linux */ |
|
336 |
|
337 /* |
|
338 * Prevent recursions. Since LD_LIBRARY_PATH is the one which will be set by |
|
339 * previous versions of the JRE, thus it is the only path that matters here. |
|
340 * So we check to see if the desired JRE is set. |
|
341 */ |
|
342 JLI_StrNCpy(jpath, jvmpath, PATH_MAX); |
|
343 p = JLI_StrRChr(jpath, '/'); |
|
344 *p = '\0'; |
|
345 if (llp != NULL && JLI_StrNCmp(llp, jpath, JLI_StrLen(jpath)) == 0) { |
|
346 return JNI_FALSE; |
|
347 } |
|
348 |
|
349 /* scrutinize all the paths further */ |
|
350 if (llp != NULL && ContainsLibJVM(wanted, llp)) { |
|
351 return JNI_TRUE; |
|
352 } |
|
353 if (dmllp != NULL && ContainsLibJVM(wanted, dmllp)) { |
|
354 return JNI_TRUE; |
|
355 } |
|
356 return JNI_FALSE; |
|
357 } |
|
358 #endif /* SETENV_REQUIRED */ |
184 |
359 |
185 void |
360 void |
186 CreateExecutionEnvironment(int *pargc, char ***pargv, |
361 CreateExecutionEnvironment(int *pargc, char ***pargv, |
187 char jrepath[], jint so_jrepath, |
362 char jrepath[], jint so_jrepath, |
188 char jvmpath[], jint so_jvmpath) { |
363 char jvmpath[], jint so_jvmpath) { |
329 exit(4); |
523 exit(4); |
330 } |
524 } |
331 |
525 |
332 /* exec child can do error checking on the existence of the path */ |
526 /* exec child can do error checking on the existence of the path */ |
333 jvmpathExists = GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, GetArchPath(wanted)); |
527 jvmpathExists = GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, GetArchPath(wanted)); |
334 |
528 #ifdef SETENV_REQUIRED |
|
529 mustsetenv = RequiresSetenv(wanted, jvmpath); |
|
530 #endif /* SETENV_REQUIRED */ |
335 } |
531 } |
336 #else |
532 #else |
337 JLI_ReportErrorMessage(JRE_ERROR2, wanted); |
533 JLI_ReportErrorMessage(JRE_ERROR2, wanted); |
338 exit(1); |
534 exit(1); |
339 #endif |
535 #endif |
340 } |
536 } |
341 |
537 #ifdef SETENV_REQUIRED |
342 { |
538 if (mustsetenv) { |
343 char *newexec = execname; |
539 /* |
|
540 * We will set the LD_LIBRARY_PATH as follows: |
|
541 * |
|
542 * o $JVMPATH (directory portion only) |
|
543 * o $JRE/lib/$LIBARCHNAME |
|
544 * o $JRE/../lib/$LIBARCHNAME |
|
545 * |
|
546 * followed by the user's previous effective LD_LIBRARY_PATH, if |
|
547 * any. |
|
548 */ |
|
549 |
|
550 #ifdef __solaris__ |
|
551 /* |
|
552 * Starting in Solaris 7, ld.so.1 supports three LD_LIBRARY_PATH |
|
553 * variables: |
|
554 * |
|
555 * 1. LD_LIBRARY_PATH -- used for 32 and 64 bit searches if |
|
556 * data-model specific variables are not set. |
|
557 * |
|
558 * 2. LD_LIBRARY_PATH_64 -- overrides and replaces LD_LIBRARY_PATH |
|
559 * for 64-bit binaries. |
|
560 * |
|
561 * 3. LD_LIBRARY_PATH_32 -- overrides and replaces LD_LIBRARY_PATH |
|
562 * for 32-bit binaries. |
|
563 * |
|
564 * The vm uses LD_LIBRARY_PATH to set the java.library.path system |
|
565 * property. To shield the vm from the complication of multiple |
|
566 * LD_LIBRARY_PATH variables, if the appropriate data model |
|
567 * specific variable is set, we will act as if LD_LIBRARY_PATH had |
|
568 * the value of the data model specific variant and the data model |
|
569 * specific variant will be unset. Note that the variable for the |
|
570 * *wanted* data model must be used (if it is set), not simply the |
|
571 * current running data model. |
|
572 */ |
|
573 |
|
574 switch (wanted) { |
|
575 case 0: |
|
576 if (running == 32) { |
|
577 dmpath = getenv("LD_LIBRARY_PATH_32"); |
|
578 wanted = 32; |
|
579 } else { |
|
580 dmpath = getenv("LD_LIBRARY_PATH_64"); |
|
581 wanted = 64; |
|
582 } |
|
583 break; |
|
584 |
|
585 case 32: |
|
586 dmpath = getenv("LD_LIBRARY_PATH_32"); |
|
587 break; |
|
588 |
|
589 case 64: |
|
590 dmpath = getenv("LD_LIBRARY_PATH_64"); |
|
591 break; |
|
592 |
|
593 default: |
|
594 JLI_ReportErrorMessage(JRE_ERROR3, __LINE__); |
|
595 exit(1); /* unknown value in wanted */ |
|
596 break; |
|
597 } |
|
598 |
|
599 /* |
|
600 * If dmpath is NULL, the relevant data model specific variable is |
|
601 * not set and normal LD_LIBRARY_PATH should be used. |
|
602 */ |
|
603 if (dmpath == NULL) { |
|
604 runpath = getenv("LD_LIBRARY_PATH"); |
|
605 } else { |
|
606 runpath = dmpath; |
|
607 } |
|
608 #else |
|
609 /* |
|
610 * If not on Solaris, assume only a single LD_LIBRARY_PATH |
|
611 * variable. |
|
612 */ |
|
613 runpath = getenv("LD_LIBRARY_PATH"); |
|
614 #endif /* __solaris__ */ |
|
615 |
|
616 /* runpath contains current effective LD_LIBRARY_PATH setting */ |
|
617 |
|
618 jvmpath = JLI_StringDup(jvmpath); |
|
619 new_runpath = JLI_MemAlloc(((runpath != NULL) ? JLI_StrLen(runpath) : 0) + |
|
620 2 * JLI_StrLen(jrepath) + 2 * JLI_StrLen(arch) + |
|
621 JLI_StrLen(jvmpath) + 52); |
|
622 newpath = new_runpath + JLI_StrLen("LD_LIBRARY_PATH="); |
|
623 |
|
624 |
|
625 /* |
|
626 * Create desired LD_LIBRARY_PATH value for target data model. |
|
627 */ |
|
628 { |
|
629 /* remove the name of the .so from the JVM path */ |
|
630 lastslash = JLI_StrRChr(jvmpath, '/'); |
|
631 if (lastslash) |
|
632 *lastslash = '\0'; |
|
633 |
|
634 sprintf(new_runpath, "LD_LIBRARY_PATH=" |
|
635 "%s:" |
|
636 "%s/lib/%s:" |
|
637 "%s/../lib/%s", |
|
638 jvmpath, |
344 #ifdef DUAL_MODE |
639 #ifdef DUAL_MODE |
345 /* |
640 jrepath, GetArchPath(wanted), |
346 * If the data model is being changed, the path to the |
641 jrepath, GetArchPath(wanted) |
347 * executable must be updated accordingly; the executable name |
642 #else |
348 * and directory the executable resides in are separate. In the |
643 jrepath, arch, |
349 * case of 32 => 64, the new bits are assumed to reside in, e.g. |
644 jrepath, arch |
350 * "olddir/LIBARCH64NAME/execname"; in the case of 64 => 32, |
|
351 * the bits are assumed to be in "olddir/../execname". For example, |
|
352 * |
|
353 * olddir/sparcv9/execname |
|
354 * olddir/amd64/execname |
|
355 * |
|
356 * for Solaris SPARC and Linux amd64, respectively. |
|
357 */ |
|
358 |
|
359 if (running != wanted) { |
|
360 char *oldexec = JLI_StrCpy(JLI_MemAlloc(JLI_StrLen(execname) + 1), execname); |
|
361 char *olddir = oldexec; |
|
362 char *oldbase = JLI_StrRChr(oldexec, '/'); |
|
363 |
|
364 |
|
365 newexec = JLI_MemAlloc(JLI_StrLen(execname) + 20); |
|
366 *oldbase++ = 0; |
|
367 sprintf(newexec, "%s/%s/%s", olddir, |
|
368 ((wanted==64) ? LIBARCH64NAME : ".."), oldbase); |
|
369 argv[0] = newexec; |
|
370 } |
|
371 #endif |
645 #endif |
372 JLI_TraceLauncher("TRACER_MARKER:About to EXEC\n"); |
646 ); |
373 (void)fflush(stdout); |
647 |
374 (void)fflush(stderr); |
648 |
375 execv(newexec, argv); |
649 /* |
376 JLI_ReportErrorMessageSys(JRE_ERROR4, newexec); |
650 * Check to make sure that the prefix of the current path is the |
377 |
651 * desired environment variable setting, though the RequiresSetenv |
|
652 * checks if the desired runpath exists, this logic does a more |
|
653 * comprehensive check. |
|
654 */ |
|
655 if (runpath != NULL && |
|
656 JLI_StrNCmp(newpath, runpath, JLI_StrLen(newpath)) == 0 && |
|
657 (runpath[JLI_StrLen(newpath)] == 0 || runpath[JLI_StrLen(newpath)] == ':') && |
|
658 (running == wanted) /* data model does not have to be changed */ |
|
659 #ifdef __solaris__ |
|
660 && (dmpath == NULL) /* data model specific variables not set */ |
|
661 #endif |
|
662 ) { |
|
663 |
|
664 return; |
|
665 |
|
666 } |
|
667 } |
|
668 |
|
669 /* |
|
670 * Place the desired environment setting onto the prefix of |
|
671 * LD_LIBRARY_PATH. Note that this prevents any possible infinite |
|
672 * loop of execv() because we test for the prefix, above. |
|
673 */ |
|
674 if (runpath != 0) { |
|
675 JLI_StrCat(new_runpath, ":"); |
|
676 JLI_StrCat(new_runpath, runpath); |
|
677 } |
|
678 |
|
679 if (putenv(new_runpath) != 0) { |
|
680 exit(1); /* problem allocating memory; LD_LIBRARY_PATH not set |
|
681 properly */ |
|
682 } |
|
683 |
|
684 /* |
|
685 * Unix systems document that they look at LD_LIBRARY_PATH only |
|
686 * once at startup, so we have to re-exec the current executable |
|
687 * to get the changed environment variable to have an effect. |
|
688 */ |
|
689 |
|
690 #ifdef __solaris__ |
|
691 /* |
|
692 * If dmpath is not NULL, remove the data model specific string |
|
693 * in the environment for the exec'ed child. |
|
694 */ |
|
695 if (dmpath != NULL) |
|
696 (void)UnsetEnv((wanted == 32) ? "LD_LIBRARY_PATH_32" : "LD_LIBRARY_PATH_64"); |
|
697 #endif |
|
698 |
|
699 newenvp = environ; |
|
700 } |
|
701 #endif /* SETENV_REQUIRED */ |
|
702 { |
|
703 char *newexec = execname; |
378 #ifdef DUAL_MODE |
704 #ifdef DUAL_MODE |
379 if (running != wanted) { |
705 /* |
380 JLI_ReportErrorMessage(JRE_ERROR5, wanted, running); |
706 * If the data model is being changed, the path to the |
381 # ifdef __solaris__ |
707 * executable must be updated accordingly; the executable name |
382 # ifdef __sparc |
708 * and directory the executable resides in are separate. In the |
383 JLI_ReportErrorMessage(JRE_ERROR6); |
709 * case of 32 => 64, the new bits are assumed to reside in, e.g. |
384 # else |
710 * "olddir/LIBARCH64NAME/execname"; in the case of 64 => 32, |
385 JLI_ReportErrorMessage(JRE_ERROR7); |
711 * the bits are assumed to be in "olddir/../execname". For example, |
386 # endif |
712 * |
387 } |
713 * olddir/sparcv9/execname |
388 # endif |
714 * olddir/amd64/execname |
389 #endif |
715 * |
390 |
716 * for Solaris SPARC and Linux amd64, respectively. |
391 } |
717 */ |
392 exit(1); |
718 |
393 } |
719 if (running != wanted) { |
394 |
720 char *oldexec = JLI_StrCpy(JLI_MemAlloc(JLI_StrLen(execname) + 1), execname); |
|
721 char *olddir = oldexec; |
|
722 char *oldbase = JLI_StrRChr(oldexec, '/'); |
|
723 |
|
724 |
|
725 newexec = JLI_MemAlloc(JLI_StrLen(execname) + 20); |
|
726 *oldbase++ = 0; |
|
727 sprintf(newexec, "%s/%s/%s", olddir, |
|
728 ((wanted == 64) ? LIBARCH64NAME : ".."), oldbase); |
|
729 argv[0] = newexec; |
|
730 } |
|
731 #endif /* DUAL_MODE */ |
|
732 JLI_TraceLauncher("TRACER_MARKER:About to EXEC\n"); |
|
733 (void) fflush(stdout); |
|
734 (void) fflush(stderr); |
|
735 #ifdef SETENV_REQUIRED |
|
736 if (mustsetenv) { |
|
737 execve(newexec, argv, newenvp); |
|
738 } else { |
|
739 execv(newexec, argv); |
|
740 } |
|
741 #else |
|
742 execv(newexec, argv); |
|
743 #endif /* SETENV_REQUIRED */ |
|
744 JLI_ReportErrorMessageSys(JRE_ERROR4, newexec); |
|
745 |
|
746 #ifdef DUAL_MODE |
|
747 if (running != wanted) { |
|
748 JLI_ReportErrorMessage(JRE_ERROR5, wanted, running); |
|
749 #ifdef __solaris__ |
|
750 #ifdef __sparc |
|
751 JLI_ReportErrorMessage(JRE_ERROR6); |
|
752 #else |
|
753 JLI_ReportErrorMessage(JRE_ERROR7); |
|
754 #endif /* __sparc */ |
|
755 } |
|
756 #endif /* __solaris__ */ |
|
757 #endif /* DUAL_MODE */ |
|
758 |
|
759 } |
|
760 exit(1); |
|
761 } |
395 } |
762 } |
396 |
763 |
397 /* |
764 /* |
398 * On Solaris VM choosing is done by the launcher (java.c). |
765 * On Solaris VM choosing is done by the launcher (java.c). |
399 */ |
766 */ |