1 /*
2  * Copyright (c) 1998, 2017, 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 #include "java.h"
27 #include "jvm_md.h"
28 #include <dirent.h>
29 #include <dlfcn.h>
30 #include <fcntl.h>
31 #include <inttypes.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37 #include <sys/types.h>
38 #ifdef __DragonFly__
39 #include <sys/sysctl.h>
40 #endif
41 #ifdef __FreeBSD__
42 #include <sys/sysctl.h>
43 #include <sys/procctl.h>
44 #ifndef PROC_STACKGAP_DISABLE
45 #define PROC_STACKGAP_DISABLE	0x0002
46 #endif
47 #ifndef PROC_STACKGAP_CTL
48 #define PROC_STACKGAP_CTL	17
49 #endif
50 #endif /* __FreeBSD__ */
51 #include "manifest_info.h"
52 
53 
54 #define JVM_DLL "libjvm.so"
55 #define JAVA_DLL "libjava.so"
56 #ifdef AIX
57 #define LD_LIBRARY_PATH "LIBPATH"
58 #else
59 #define LD_LIBRARY_PATH "LD_LIBRARY_PATH"
60 #endif
61 
62 /* help jettison the LD_LIBRARY_PATH settings in the future */
63 #ifndef SETENV_REQUIRED
64 #define SETENV_REQUIRED
65 #endif
66 
67 #ifdef __solaris__
68 #  include <sys/systeminfo.h>
69 #  include <sys/elf.h>
70 #  include <stdio.h>
71 #endif
72 
73 /*
74  * Flowchart of launcher execs and options processing on unix
75  *
76  * The selection of the proper vm shared library to open depends on
77  * several classes of command line options, including vm "flavor"
78  * options (-client, -server).
79  * The vm selection options are not passed to the running
80  * virtual machine; they must be screened out by the launcher.
81  *
82  * The version specification (if any) is processed first by the
83  * platform independent routine SelectVersion.  This may result in
84  * the exec of the specified launcher version.
85  *
86  * Previously the launcher modified the LD_LIBRARY_PATH appropriately for the
87  * desired data model path, regardless if data models matched or not. The
88  * launcher subsequently exec'ed the desired executable, in order to make the
89  * LD_LIBRARY_PATH path available, for the runtime linker.
90  *
91  * Now, in most cases,the launcher will dlopen the target libjvm.so. All
92  * required libraries are loaded by the runtime linker, using the
93  * $RPATH/$ORIGIN baked into the shared libraries at compile time. Therefore,
94  * in most cases, the launcher will only exec, if the data models are
95  * mismatched, and will not set any environment variables, regardless of the
96  * data models.
97  *
98  * However, if the environment contains a LD_LIBRARY_PATH, this will cause the
99  * launcher to inspect the LD_LIBRARY_PATH. The launcher will check
100  *  a. if the LD_LIBRARY_PATH's first component is the path to the desired
101  *     libjvm.so
102  *  b. if any other libjvm.so is found in any of the paths.
103  * If case b is true, then the launcher will set the LD_LIBRARY_PATH to the
104  * desired JRE and reexec, in order to propagate the environment.
105  *
106  *  Main
107  *  (incoming argv)
108  *  |
109  * \|/
110  * CreateExecutionEnvironment
111  * (determines desired data model)
112  *  |
113  *  |
114  * \|/
115  *  Have Desired Model ? --> NO --> Exit(with error)
116  *  |
117  *  |
118  * \|/
119  * YES
120  *  |
121  *  |
122  * \|/
123  * CheckJvmType
124  * (removes -client, -server, etc.)
125  *  |
126  *  |
127  * \|/
128  * TranslateDashJArgs...
129  * (Prepare to pass args to vm)
130  *  |
131  *  |
132  * \|/
133  * ParseArguments
134  *   |
135  *   |
136  *  \|/
137  * RequiresSetenv
138  * Is LD_LIBRARY_PATH
139  * and friends set ? --> NO --> Continue
140  *  YES
141  *   |
142  *   |
143  *  \|/
144  * Path is desired JRE ? YES --> Continue
145  *  NO
146  *   |
147  *   |
148  *  \|/
149  * Paths have well known
150  * jvm paths ?       --> NO --> Error/Exit
151  *  YES
152  *   |
153  *   |
154  *  \|/
155  *  Does libjvm.so exist
156  *  in any of them ? --> NO  --> Continue
157  *   YES
158  *   |
159  *   |
160  *  \|/
161  *  Set the LD_LIBRARY_PATH
162  *   |
163  *   |
164  *  \|/
165  * Re-exec
166  *   |
167  *   |
168  *  \|/
169  * Main
170  */
171 
172 /* Store the name of the executable once computed */
173 static char *execname = NULL;
174 
175 /*
176  * execname accessor from other parts of platform dependent logic
177  */
178 const char *
GetExecName()179 GetExecName() {
180     return execname;
181 }
182 
183 #ifdef SETENV_REQUIRED
184 static jboolean
JvmExists(const char * path)185 JvmExists(const char *path) {
186     char tmp[PATH_MAX + 1];
187     struct stat statbuf;
188     JLI_Snprintf(tmp, PATH_MAX, "%s/%s", path, JVM_DLL);
189     if (stat(tmp, &statbuf) == 0) {
190         return JNI_TRUE;
191     }
192     return JNI_FALSE;
193 }
194 /*
195  * contains a lib/{server,client}/libjvm.so ?
196  */
197 static jboolean
ContainsLibJVM(const char * env)198 ContainsLibJVM(const char *env) {
199     /* the usual suspects */
200     char clientPattern[] = "lib/client";
201     char serverPattern[] = "lib/server";
202     char *envpath;
203     char *path;
204     jboolean clientPatternFound;
205     jboolean serverPatternFound;
206 
207     /* fastest path */
208     if (env == NULL) {
209         return JNI_FALSE;
210     }
211 
212     /* to optimize for time, test if any of our usual suspects are present. */
213     clientPatternFound = JLI_StrStr(env, clientPattern) != NULL;
214     serverPatternFound = JLI_StrStr(env, serverPattern) != NULL;
215     if (clientPatternFound == JNI_FALSE && serverPatternFound == JNI_FALSE) {
216         return JNI_FALSE;
217     }
218 
219     /*
220      * we have a suspicious path component, check if it contains a libjvm.so
221      */
222     envpath = JLI_StringDup(env);
223     for (path = JLI_StrTok(envpath, ":"); path != NULL; path = JLI_StrTok(NULL, ":")) {
224         if (clientPatternFound && JLI_StrStr(path, clientPattern) != NULL) {
225             if (JvmExists(path)) {
226                 JLI_MemFree(envpath);
227                 return JNI_TRUE;
228             }
229         }
230         if (serverPatternFound && JLI_StrStr(path, serverPattern)  != NULL) {
231             if (JvmExists(path)) {
232                 JLI_MemFree(envpath);
233                 return JNI_TRUE;
234             }
235         }
236     }
237     JLI_MemFree(envpath);
238     return JNI_FALSE;
239 }
240 
241 /*
242  * Test whether the environment variable needs to be set, see flowchart.
243  */
244 static jboolean
RequiresSetenv(const char * jvmpath)245 RequiresSetenv(const char *jvmpath) {
246     char jpath[PATH_MAX + 1];
247     char *llp;
248     char *dmllp = NULL;
249     char *p; /* a utility pointer */
250 
251 #ifdef AIX
252     /* We always have to set the LIBPATH on AIX because ld doesn't support $ORIGIN. */
253     return JNI_TRUE;
254 #endif
255 
256     llp = getenv("LD_LIBRARY_PATH");
257 #ifdef __solaris__
258     dmllp = getenv("LD_LIBRARY_PATH_64");
259 #endif /* __solaris__ */
260     /* no environment variable is a good environment variable */
261     if (llp == NULL && dmllp == NULL) {
262         return JNI_FALSE;
263     }
264 #ifdef __linux
265     /*
266      * On linux, if a binary is running as sgid or suid, glibc sets
267      * LD_LIBRARY_PATH to the empty string for security purposes. (In contrast,
268      * on Solaris the LD_LIBRARY_PATH variable for a privileged binary does not
269      * lose its settings; but the dynamic linker does apply more scrutiny to the
270      * path.) The launcher uses the value of LD_LIBRARY_PATH to prevent an exec
271      * loop, here and further downstream. Therefore, if we are running sgid or
272      * suid, this function's setting of LD_LIBRARY_PATH will be ineffective and
273      * we should case a return from the calling function.  Getting the right
274      * libraries will be handled by the RPATH. In reality, this check is
275      * redundant, as the previous check for a non-null LD_LIBRARY_PATH will
276      * return back to the calling function forthwith, it is left here to safe
277      * guard against any changes, in the glibc's existing security policy.
278      */
279     if ((getgid() != getegid()) || (getuid() != geteuid())) {
280         return JNI_FALSE;
281     }
282 #endif /* __linux */
283 
284 #ifdef _BSDONLY_SOURCE
285     /*
286      * The BSD's (except MacOSX which doesn't include this file), also clear
287      * LD_LIBRARY_PATH when a binary is running setuid or setgid.
288      */
289     if (issetugid()) {
290      return JNI_FALSE;
291     }
292 #endif /* _BSDONLY_SOURCE */
293 
294     /*
295      * Prevent recursions. Since LD_LIBRARY_PATH is the one which will be set by
296      * previous versions of the JRE, thus it is the only path that matters here.
297      * So we check to see if the desired JRE is set.
298      */
299     JLI_StrNCpy(jpath, jvmpath, PATH_MAX);
300     p = JLI_StrRChr(jpath, '/');
301     *p = '\0';
302     if (llp != NULL && JLI_StrNCmp(llp, jpath, JLI_StrLen(jpath)) == 0) {
303         return JNI_FALSE;
304     }
305 
306     /* scrutinize all the paths further */
307     if (llp != NULL &&  ContainsLibJVM(llp)) {
308         return JNI_TRUE;
309     }
310     if (dmllp != NULL && ContainsLibJVM(dmllp)) {
311         return JNI_TRUE;
312     }
313     return JNI_FALSE;
314 }
315 #endif /* SETENV_REQUIRED */
316 
317 void
CreateExecutionEnvironment(int * pargc,char *** pargv,char jrepath[],jint so_jrepath,char jvmpath[],jint so_jvmpath,char jvmcfg[],jint so_jvmcfg)318 CreateExecutionEnvironment(int *pargc, char ***pargv,
319                            char jrepath[], jint so_jrepath,
320                            char jvmpath[], jint so_jvmpath,
321                            char jvmcfg[],  jint so_jvmcfg) {
322 
323     char * jvmtype = NULL;
324     int argc = *pargc;
325     char **argv = *pargv;
326 
327 #ifdef SETENV_REQUIRED
328     jboolean mustsetenv = JNI_FALSE;
329     char *runpath = NULL; /* existing effective LD_LIBRARY_PATH setting */
330     char* new_runpath = NULL; /* desired new LD_LIBRARY_PATH string */
331     char* newpath = NULL; /* path on new LD_LIBRARY_PATH */
332     char* lastslash = NULL;
333     char** newenvp = NULL; /* current environment */
334     size_t new_runpath_size;
335 #endif  /* SETENV_REQUIRED */
336 
337     /* Compute/set the name of the executable */
338     SetExecname(*pargv);
339 
340     /* Check to see if the jvmpath exists */
341     /* Find out where the JRE is that we will be using. */
342     if (!GetJREPath(jrepath, so_jrepath, JNI_FALSE)) {
343         JLI_ReportErrorMessage(JRE_ERROR1);
344         exit(2);
345     }
346     JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%sjvm.cfg",
347             jrepath, FILESEP, FILESEP);
348     /* Find the specified JVM type */
349     if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) {
350         JLI_ReportErrorMessage(CFG_ERROR7);
351         exit(1);
352     }
353 
354     jvmpath[0] = '\0';
355     jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE);
356     if (JLI_StrCmp(jvmtype, "ERROR") == 0) {
357         JLI_ReportErrorMessage(CFG_ERROR9);
358         exit(4);
359     }
360 
361     if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath)) {
362         JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath);
363         exit(4);
364     }
365     /*
366      * we seem to have everything we need, so without further ado
367      * we return back, otherwise proceed to set the environment.
368      */
369 #ifdef SETENV_REQUIRED
370     mustsetenv = RequiresSetenv(jvmpath);
371     JLI_TraceLauncher("mustsetenv: %s\n", mustsetenv ? "TRUE" : "FALSE");
372 
373     if (mustsetenv == JNI_FALSE) {
374         return;
375     }
376 #else
377     return;
378 #endif /* SETENV_REQUIRED */
379 
380 #ifdef SETENV_REQUIRED
381     if (mustsetenv) {
382         /*
383          * We will set the LD_LIBRARY_PATH as follows:
384          *
385          *     o          $JVMPATH (directory portion only)
386          *     o          $JRE/lib
387          *     o          $JRE/../lib
388          *
389          * followed by the user's previous effective LD_LIBRARY_PATH, if
390          * any.
391          */
392 
393         runpath = getenv(LD_LIBRARY_PATH);
394 
395         /* runpath contains current effective LD_LIBRARY_PATH setting */
396         { /* New scope to declare local variable */
397             char *new_jvmpath = JLI_StringDup(jvmpath);
398             new_runpath_size = ((runpath != NULL) ? JLI_StrLen(runpath) : 0) +
399                     2 * JLI_StrLen(jrepath) +
400 #ifdef AIX
401                     /* On AIX we additionally need 'jli' in the path because ld doesn't support $ORIGIN. */
402                     JLI_StrLen(jrepath) + JLI_StrLen("/lib//jli:") +
403 #endif
404                     JLI_StrLen(new_jvmpath) + 52;
405             new_runpath = JLI_MemAlloc(new_runpath_size);
406             newpath = new_runpath + JLI_StrLen(LD_LIBRARY_PATH "=");
407 
408 
409             /*
410              * Create desired LD_LIBRARY_PATH value for target data model.
411              */
412             {
413                 /* remove the name of the .so from the JVM path */
414                 lastslash = JLI_StrRChr(new_jvmpath, '/');
415                 if (lastslash)
416                     *lastslash = '\0';
417 
418                 sprintf(new_runpath, LD_LIBRARY_PATH "="
419                         "%s:"
420                         "%s/lib:"
421 #ifdef AIX
422                         "%s/lib/jli:" /* Needed on AIX because ld doesn't support $ORIGIN. */
423 #endif
424                         "%s/../lib",
425                         new_jvmpath,
426                         jrepath,
427 #ifdef AIX
428                         jrepath,
429 #endif
430                         jrepath
431                         );
432 
433                 JLI_MemFree(new_jvmpath);
434 
435                 /*
436                  * Check to make sure that the prefix of the current path is the
437                  * desired environment variable setting, though the RequiresSetenv
438                  * checks if the desired runpath exists, this logic does a more
439                  * comprehensive check.
440                  */
441                 if (runpath != NULL &&
442                         JLI_StrNCmp(newpath, runpath, JLI_StrLen(newpath)) == 0 &&
443                         (runpath[JLI_StrLen(newpath)] == 0 ||
444                         runpath[JLI_StrLen(newpath)] == ':')) {
445                     JLI_MemFree(new_runpath);
446                     return;
447                 }
448             }
449         }
450 
451         /*
452          * Place the desired environment setting onto the prefix of
453          * LD_LIBRARY_PATH.  Note that this prevents any possible infinite
454          * loop of execv() because we test for the prefix, above.
455          */
456         if (runpath != 0) {
457             /* ensure storage for runpath + colon + NULL */
458             if ((JLI_StrLen(runpath) + 1 + 1) > new_runpath_size) {
459                 JLI_ReportErrorMessageSys(JRE_ERROR11);
460                 exit(1);
461             }
462             JLI_StrCat(new_runpath, ":");
463             JLI_StrCat(new_runpath, runpath);
464         }
465 
466         if (putenv(new_runpath) != 0) {
467             /* problem allocating memory; LD_LIBRARY_PATH not set properly */
468             exit(1);
469         }
470 
471         /*
472          * Unix systems document that they look at LD_LIBRARY_PATH only
473          * once at startup, so we have to re-exec the current executable
474          * to get the changed environment variable to have an effect.
475          */
476 
477         newenvp = environ;
478     }
479 #endif /* SETENV_REQUIRED */
480     {
481         char *newexec = execname;
482         JLI_TraceLauncher("TRACER_MARKER:About to EXEC\n");
483         (void) fflush(stdout);
484         (void) fflush(stderr);
485 #ifdef SETENV_REQUIRED
486         if (mustsetenv) {
487             execve(newexec, argv, newenvp);
488         } else {
489             execv(newexec, argv);
490         }
491 #else /* !SETENV_REQUIRED */
492         execv(newexec, argv);
493 #endif /* SETENV_REQUIRED */
494         JLI_ReportErrorMessageSys(JRE_ERROR4, newexec);
495     }
496     exit(1);
497 }
498 
499 
500 static jboolean
GetJVMPath(const char * jrepath,const char * jvmtype,char * jvmpath,jint jvmpathsize)501 GetJVMPath(const char *jrepath, const char *jvmtype,
502            char *jvmpath, jint jvmpathsize)
503 {
504     struct stat s;
505 
506     if (JLI_StrChr(jvmtype, '/')) {
507         JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype);
508     } else {
509         JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/" JVM_DLL, jrepath, jvmtype);
510     }
511 
512     JLI_TraceLauncher("Does `%s' exist ... ", jvmpath);
513 
514     if (stat(jvmpath, &s) == 0) {
515         JLI_TraceLauncher("yes.\n");
516         return JNI_TRUE;
517     } else {
518         JLI_TraceLauncher("no.\n");
519         return JNI_FALSE;
520     }
521 }
522 
523 /*
524  * Find path to JRE based on .exe's location or registry settings.
525  */
526 static jboolean
GetJREPath(char * path,jint pathsize,jboolean speculative)527 GetJREPath(char *path, jint pathsize, jboolean speculative)
528 {
529     char libjava[MAXPATHLEN];
530     struct stat s;
531 
532     if (GetApplicationHome(path, pathsize)) {
533         /* Is JRE co-located with the application? */
534         JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);
535         if (access(libjava, F_OK) == 0) {
536             JLI_TraceLauncher("JRE path is %s\n", path);
537             return JNI_TRUE;
538         }
539         /* ensure storage for path + /jre + NULL */
540         if ((JLI_StrLen(path) + 4  + 1) > (size_t) pathsize) {
541             JLI_TraceLauncher("Insufficient space to store JRE path\n");
542             return JNI_FALSE;
543         }
544         /* Does the app ship a private JRE in <apphome>/jre directory? */
545         JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/" JAVA_DLL, path);
546         if (access(libjava, F_OK) == 0) {
547             JLI_StrCat(path, "/jre");
548             JLI_TraceLauncher("JRE path is %s\n", path);
549             return JNI_TRUE;
550         }
551     }
552 
553     if (GetApplicationHomeFromDll(path, pathsize)) {
554         JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);
555         if (stat(libjava, &s) == 0) {
556             JLI_TraceLauncher("JRE path is %s\n", path);
557             return JNI_TRUE;
558         }
559     }
560 
561     if (!speculative)
562       JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL);
563     return JNI_FALSE;
564 }
565 
566 jboolean
LoadJavaVM(const char * jvmpath,InvocationFunctions * ifn)567 LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)
568 {
569     void *libjvm;
570 
571     JLI_TraceLauncher("JVM path is %s\n", jvmpath);
572 
573     libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);
574     if (libjvm == NULL) {
575 #if defined(__solaris__) && defined(__sparc) && !defined(_LP64) /* i.e. 32-bit sparc */
576       FILE * fp;
577       Elf32_Ehdr elf_head;
578       int count;
579       int location;
580 
581       fp = fopen(jvmpath, "r");
582       if (fp == NULL) {
583         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
584         return JNI_FALSE;
585       }
586 
587       /* read in elf header */
588       count = fread((void*)(&elf_head), sizeof(Elf32_Ehdr), 1, fp);
589       fclose(fp);
590       if (count < 1) {
591         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
592         return JNI_FALSE;
593       }
594 
595       /*
596        * Check for running a server vm (compiled with -xarch=v8plus)
597        * on a stock v8 processor.  In this case, the machine type in
598        * the elf header would not be included the architecture list
599        * provided by the isalist command, which is turn is gotten from
600        * sysinfo.  This case cannot occur on 64-bit hardware and thus
601        * does not have to be checked for in binaries with an LP64 data
602        * model.
603        */
604       if (elf_head.e_machine == EM_SPARC32PLUS) {
605         char buf[257];  /* recommended buffer size from sysinfo man
606                            page */
607         long length;
608         char* location;
609 
610         length = sysinfo(SI_ISALIST, buf, 257);
611         if (length > 0) {
612             location = JLI_StrStr(buf, "sparcv8plus ");
613           if (location == NULL) {
614             JLI_ReportErrorMessage(JVM_ERROR3);
615             return JNI_FALSE;
616           }
617         }
618       }
619 #endif
620         JLI_ReportErrorMessage(DLL_ERROR1, __LINE__);
621         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
622         return JNI_FALSE;
623     }
624 
625     ifn->CreateJavaVM = (CreateJavaVM_t)
626         dlsym(libjvm, "JNI_CreateJavaVM");
627     if (ifn->CreateJavaVM == NULL) {
628         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
629         return JNI_FALSE;
630     }
631 
632     ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)
633         dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");
634     if (ifn->GetDefaultJavaVMInitArgs == NULL) {
635         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
636         return JNI_FALSE;
637     }
638 
639     ifn->GetCreatedJavaVMs = (GetCreatedJavaVMs_t)
640         dlsym(libjvm, "JNI_GetCreatedJavaVMs");
641     if (ifn->GetCreatedJavaVMs == NULL) {
642         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
643         return JNI_FALSE;
644     }
645 
646     return JNI_TRUE;
647 }
648 
649 /*
650  * Compute the name of the executable
651  *
652  * In order to re-exec securely we need the absolute path of the
653  * executable. On Solaris getexecname(3c) may not return an absolute
654  * path so we use dladdr to get the filename of the executable and
655  * then use realpath to derive an absolute path. From Solaris 9
656  * onwards the filename returned in DL_info structure from dladdr is
657  * an absolute pathname so technically realpath isn't required.
658  * On Linux we read the executable name from /proc/self/exe.
659  * On FreeBSD, we get the executable name via sysctl(3).
660  * As a fallback, and for platforms other than Solaris, Linux, and
661  * FreeBSD we use FindExecName to compute the executable name.
662  */
663 const char*
SetExecname(char ** argv)664 SetExecname(char **argv)
665 {
666     char* exec_path = NULL;
667 #if defined(__solaris__)
668     {
669         Dl_info dlinfo;
670         int (*fptr)();
671 
672         fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");
673         if (fptr == NULL) {
674             JLI_ReportErrorMessage(DLL_ERROR3, dlerror());
675             return JNI_FALSE;
676         }
677 
678         if (dladdr((void*)fptr, &dlinfo)) {
679             char *resolved = (char*)JLI_MemAlloc(PATH_MAX+1);
680             if (resolved != NULL) {
681                 exec_path = realpath(dlinfo.dli_fname, resolved);
682                 if (exec_path == NULL) {
683                     JLI_MemFree(resolved);
684                 }
685             }
686         }
687     }
688 #elif defined(__linux__)
689     {
690         const char* self = "/proc/self/exe";
691         char buf[PATH_MAX+1];
692         int len = readlink(self, buf, PATH_MAX);
693         if (len >= 0) {
694             buf[len] = '\0';            /* readlink(2) doesn't NUL terminate */
695             exec_path = JLI_StringDup(buf);
696         }
697     }
698 #elif defined(__FreeBSD__) || defined(__DragonFly__)
699     {
700         char buf[PATH_MAX+1];
701         int name[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
702         size_t len = sizeof(buf);
703         if (sysctl(name, 4, buf, &len, NULL, 0) == 0 && len > 0) {
704             buf[len] = '\0';
705             exec_path = JLI_StringDup(buf);
706         }
707     }
708 #else /* !__solaris__ && !__linux__ && !__FreeBSD__ */
709     {
710         /* Not implemented */
711     }
712 #endif
713 
714     if (exec_path == NULL) {
715         exec_path = FindExecName(argv[0]);
716     }
717     execname = exec_path;
718     return exec_path;
719 }
720 
721 /* --- Splash Screen shared library support --- */
722 static const char* SPLASHSCREEN_SO = JNI_LIB_NAME("splashscreen");
723 static void* hSplashLib = NULL;
724 
SplashProcAddress(const char * name)725 void* SplashProcAddress(const char* name) {
726     if (!hSplashLib) {
727         int ret;
728         char jrePath[MAXPATHLEN];
729         char splashPath[MAXPATHLEN];
730 
731         if (!GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE)) {
732             JLI_ReportErrorMessage(JRE_ERROR1);
733             return NULL;
734         }
735         ret = JLI_Snprintf(splashPath, sizeof(splashPath), "%s/lib/%s",
736                      jrePath, SPLASHSCREEN_SO);
737 
738         if (ret >= (int) sizeof(splashPath)) {
739             JLI_ReportErrorMessage(JRE_ERROR11);
740             return NULL;
741         }
742         if (ret < 0) {
743             JLI_ReportErrorMessage(JRE_ERROR13);
744             return NULL;
745         }
746         hSplashLib = dlopen(splashPath, RTLD_LAZY | RTLD_GLOBAL);
747         JLI_TraceLauncher("Info: loaded %s\n", splashPath);
748     }
749     if (hSplashLib) {
750         void* sym = dlsym(hSplashLib, name);
751         return sym;
752     } else {
753         return NULL;
754     }
755 }
756 
SplashFreeLibrary()757 void SplashFreeLibrary() {
758     if (hSplashLib) {
759         dlclose(hSplashLib);
760         hSplashLib = NULL;
761     }
762 }
763 
764 /*
765  * Block current thread and continue execution in a new thread
766  */
767 int
ContinueInNewThread0(int (JNICALL * continuation)(void *),jlong stack_size,void * args)768 ContinueInNewThread0(int (JNICALL *continuation)(void *), jlong stack_size, void * args) {
769     int rslt;
770 #ifndef __solaris__
771     pthread_t tid;
772     pthread_attr_t attr;
773     pthread_attr_init(&attr);
774     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
775 
776     if (stack_size > 0) {
777       pthread_attr_setstacksize(&attr, stack_size);
778     }
779     pthread_attr_setguardsize(&attr, 0); // no pthread guard page on java threads
780 
781     if (pthread_create(&tid, &attr, (void *(*)(void*))continuation, (void*)args) == 0) {
782       void * tmp;
783       pthread_join(tid, &tmp);
784       rslt = (int)(intptr_t)tmp;
785     } else {
786      /*
787       * Continue execution in current thread if for some reason (e.g. out of
788       * memory/LWP)  a new thread can't be created. This will likely fail
789       * later in continuation as JNI_CreateJavaVM needs to create quite a
790       * few new threads, anyway, just give it a try..
791       */
792       rslt = continuation(args);
793     }
794 
795     pthread_attr_destroy(&attr);
796 #else /* __solaris__ */
797     thread_t tid;
798     long flags = 0;
799     if (thr_create(NULL, stack_size, (void *(*)(void *))continuation, args, flags, &tid) == 0) {
800       void * tmp;
801       thr_join(tid, NULL, &tmp);
802       rslt = (int)(intptr_t)tmp;
803     } else {
804       /* See above. Continue in current thread if thr_create() failed */
805       rslt = continuation(args);
806     }
807 #endif /* !__solaris__ */
808     return rslt;
809 }
810 
811 /* Coarse estimation of number of digits assuming the worst case is a 64-bit pid. */
812 #define MAX_PID_STR_SZ   20
813 
SetJavaLauncherPlatformProps()814 void SetJavaLauncherPlatformProps() {
815    /* Linux and BSD (execpt MaxOSX) only */
816 #if defined(__linux__) || defined(_BSDONLY_SOURCE)
817     const char *substr = "-Dsun.java.launcher.pid=";
818     char *pid_prop_str = (char *)JLI_MemAlloc(JLI_StrLen(substr) + MAX_PID_STR_SZ + 1);
819     sprintf(pid_prop_str, "%s%d", substr, getpid());
820     AddOption(pid_prop_str, NULL);
821 #endif /* __linux__ || _BSDONLY_SOURCE */
822 }
823 
824 int
JVMInit(InvocationFunctions * ifn,jlong threadStackSize,int argc,char ** argv,int mode,char * what,int ret)825 JVMInit(InvocationFunctions* ifn, jlong threadStackSize,
826         int argc, char **argv,
827         int mode, char *what, int ret)
828 {
829 #ifdef __FreeBSD__
830     /*
831      * Kernel stack guard pages interfere with the JVM's guard pages on the
832      * thread stacks and prevent correct stack overflow detection and the
833      * use of reserved pages to allow critical sections to complete.
834      *
835      * Attempt to disable the kernel stack guard pages here before any threads
836      * are created.
837      */
838     int arg = PROC_STACKGAP_DISABLE;
839     procctl(P_PID, getpid(), PROC_STACKGAP_CTL, &arg);
840 #endif
841     ShowSplashScreen();
842     return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);
843 }
844 
845 void
PostJVMInit(JNIEnv * env,jclass mainClass,JavaVM * vm)846 PostJVMInit(JNIEnv *env, jclass mainClass, JavaVM *vm)
847 {
848     // stubbed out for windows and *nixes.
849 }
850 
851 void
RegisterThread()852 RegisterThread()
853 {
854     // stubbed out for windows and *nixes.
855 }
856 
857 /*
858  * on unix, we return a false to indicate this option is not applicable
859  */
860 jboolean
ProcessPlatformOption(const char * arg)861 ProcessPlatformOption(const char *arg)
862 {
863     return JNI_FALSE;
864 }
865