1 /*
2  * Copyright (c) 1996, 2015, 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 <stdlib.h>
27 #include <assert.h>
28 
29 #include "jni.h"
30 #include "jni_util.h"
31 #include "jlong.h"
32 #include "jvm.h"
33 #include "java_lang_ClassLoader.h"
34 #include "java_lang_ClassLoader_NativeLibrary.h"
35 #include <string.h>
36 
37 /* defined in libverify.so/verify.dll (src file common/check_format.c) */
38 extern jboolean VerifyClassname(char *utf_name, jboolean arrayAllowed);
39 extern jboolean VerifyFixClassname(char *utf_name);
40 
41 static JNINativeMethod methods[] = {
42     {"retrieveDirectives",  "()Ljava/lang/AssertionStatusDirectives;", (void *)&JVM_AssertionStatusDirectives}
43 };
44 
45 JNIEXPORT void JNICALL
Java_java_lang_ClassLoader_registerNatives(JNIEnv * env,jclass cls)46 Java_java_lang_ClassLoader_registerNatives(JNIEnv *env, jclass cls)
47 {
48     (*env)->RegisterNatives(env, cls, methods,
49                             sizeof(methods)/sizeof(JNINativeMethod));
50 }
51 
52 /* Convert java string to UTF char*. Use local buffer if possible,
53    otherwise malloc new memory. Returns null IFF malloc failed. */
54 static char*
getUTF(JNIEnv * env,jstring str,char * localBuf,int bufSize)55 getUTF(JNIEnv *env, jstring str, char* localBuf, int bufSize)
56 {
57     char* utfStr = NULL;
58 
59     int len = (*env)->GetStringUTFLength(env, str);
60     int unicode_len = (*env)->GetStringLength(env, str);
61     if (len >= bufSize) {
62         utfStr = malloc(len + 1);
63         if (utfStr == NULL) {
64             JNU_ThrowOutOfMemoryError(env, NULL);
65             return NULL;
66         }
67     } else {
68         utfStr = localBuf;
69     }
70     (*env)->GetStringUTFRegion(env, str, 0, unicode_len, utfStr);
71 
72     return utfStr;
73 }
74 
75 JNIEXPORT jclass JNICALL
Java_java_lang_ClassLoader_defineClass1(JNIEnv * env,jclass cls,jobject loader,jstring name,jbyteArray data,jint offset,jint length,jobject pd,jstring source)76 Java_java_lang_ClassLoader_defineClass1(JNIEnv *env,
77                                         jclass cls,
78                                         jobject loader,
79                                         jstring name,
80                                         jbyteArray data,
81                                         jint offset,
82                                         jint length,
83                                         jobject pd,
84                                         jstring source)
85 {
86     jbyte *body;
87     char *utfName;
88     jclass result = 0;
89     char buf[128];
90     char* utfSource;
91     char sourceBuf[1024];
92 
93     if (data == NULL) {
94         JNU_ThrowNullPointerException(env, 0);
95         return 0;
96     }
97 
98     /* Work around 4153825. malloc crashes on Solaris when passed a
99      * negative size.
100      */
101     if (length < 0) {
102         JNU_ThrowArrayIndexOutOfBoundsException(env, 0);
103         return 0;
104     }
105 
106     body = (jbyte *)malloc(length);
107 
108     if (body == 0) {
109         JNU_ThrowOutOfMemoryError(env, 0);
110         return 0;
111     }
112 
113     (*env)->GetByteArrayRegion(env, data, offset, length, body);
114 
115     if ((*env)->ExceptionOccurred(env))
116         goto free_body;
117 
118     if (name != NULL) {
119         utfName = getUTF(env, name, buf, sizeof(buf));
120         if (utfName == NULL) {
121             goto free_body;
122         }
123         VerifyFixClassname(utfName);
124     } else {
125         utfName = NULL;
126     }
127 
128     if (source != NULL) {
129         utfSource = getUTF(env, source, sourceBuf, sizeof(sourceBuf));
130         if (utfSource == NULL) {
131             goto free_utfName;
132         }
133     } else {
134         utfSource = NULL;
135     }
136     result = JVM_DefineClassWithSource(env, utfName, loader, body, length, pd, utfSource);
137 
138     if (utfSource && utfSource != sourceBuf)
139         free(utfSource);
140 
141  free_utfName:
142     if (utfName && utfName != buf)
143         free(utfName);
144 
145  free_body:
146     free(body);
147     return result;
148 }
149 
150 JNIEXPORT jclass JNICALL
Java_java_lang_ClassLoader_defineClass2(JNIEnv * env,jclass cls,jobject loader,jstring name,jobject data,jint offset,jint length,jobject pd,jstring source)151 Java_java_lang_ClassLoader_defineClass2(JNIEnv *env,
152                                         jclass cls,
153                                         jobject loader,
154                                         jstring name,
155                                         jobject data,
156                                         jint offset,
157                                         jint length,
158                                         jobject pd,
159                                         jstring source)
160 {
161     jbyte *body;
162     char *utfName;
163     jclass result = 0;
164     char buf[128];
165     char* utfSource;
166     char sourceBuf[1024];
167 
168     assert(data != NULL); // caller fails if data is null.
169     assert(length >= 0);  // caller passes ByteBuffer.remaining() for length, so never neg.
170     // caller passes ByteBuffer.position() for offset, and capacity() >= position() + remaining()
171     assert((*env)->GetDirectBufferCapacity(env, data) >= (offset + length));
172 
173     body = (*env)->GetDirectBufferAddress(env, data);
174 
175     if (body == 0) {
176         JNU_ThrowNullPointerException(env, 0);
177         return 0;
178     }
179 
180     body += offset;
181 
182     if (name != NULL) {
183         utfName = getUTF(env, name, buf, sizeof(buf));
184         if (utfName == NULL) {
185             JNU_ThrowOutOfMemoryError(env, NULL);
186             return result;
187         }
188         VerifyFixClassname(utfName);
189     } else {
190         utfName = NULL;
191     }
192 
193     if (source != NULL) {
194         utfSource = getUTF(env, source, sourceBuf, sizeof(sourceBuf));
195         if (utfSource == NULL) {
196             JNU_ThrowOutOfMemoryError(env, NULL);
197             goto free_utfName;
198         }
199     } else {
200         utfSource = NULL;
201     }
202     result = JVM_DefineClassWithSource(env, utfName, loader, body, length, pd, utfSource);
203 
204     if (utfSource && utfSource != sourceBuf)
205         free(utfSource);
206 
207  free_utfName:
208     if (utfName && utfName != buf)
209         free(utfName);
210 
211     return result;
212 }
213 
214 /*
215  * Returns NULL if class not found.
216  */
217 JNIEXPORT jclass JNICALL
Java_java_lang_ClassLoader_findBootstrapClass(JNIEnv * env,jobject loader,jstring classname)218 Java_java_lang_ClassLoader_findBootstrapClass(JNIEnv *env, jobject loader,
219                                               jstring classname)
220 {
221     char *clname;
222     jclass cls = 0;
223     char buf[128];
224 
225     if (classname == NULL) {
226         return 0;
227     }
228 
229     clname = getUTF(env, classname, buf, sizeof(buf));
230     if (clname == NULL) {
231         JNU_ThrowOutOfMemoryError(env, NULL);
232         return NULL;
233     }
234     VerifyFixClassname(clname);
235 
236     if (!VerifyClassname(clname, JNI_TRUE)) {  /* expects slashed name */
237         goto done;
238     }
239 
240     cls = JVM_FindClassFromBootLoader(env, clname);
241 
242  done:
243     if (clname != buf) {
244         free(clname);
245     }
246 
247     return cls;
248 }
249 
250 JNIEXPORT jclass JNICALL
Java_java_lang_ClassLoader_findLoadedClass0(JNIEnv * env,jobject loader,jstring name)251 Java_java_lang_ClassLoader_findLoadedClass0(JNIEnv *env, jobject loader,
252                                            jstring name)
253 {
254     if (name == NULL) {
255         return 0;
256     } else {
257         return JVM_FindLoadedClass(env, loader, name);
258     }
259 }
260 
261 static jfieldID handleID;
262 static jfieldID jniVersionID;
263 static void *procHandle;
264 
initIDs(JNIEnv * env)265 static jboolean initIDs(JNIEnv *env)
266 {
267     if (handleID == 0) {
268         jclass this =
269             (*env)->FindClass(env, "java/lang/ClassLoader$NativeLibrary");
270         if (this == 0)
271             return JNI_FALSE;
272         handleID = (*env)->GetFieldID(env, this, "handle", "J");
273         if (handleID == 0)
274             return JNI_FALSE;
275         jniVersionID = (*env)->GetFieldID(env, this, "jniVersion", "I");
276         if (jniVersionID == 0)
277             return JNI_FALSE;
278         procHandle = getProcessHandle();
279     }
280     return JNI_TRUE;
281 }
282 
283 typedef jint (JNICALL *JNI_OnLoad_t)(JavaVM *, void *);
284 typedef void (JNICALL *JNI_OnUnload_t)(JavaVM *, void *);
285 
286 /*
287  * Support for finding JNI_On(Un)Load_<lib_name> if it exists.
288  * If cname == NULL then just find normal JNI_On(Un)Load entry point
289  */
findJniFunction(JNIEnv * env,void * handle,const char * cname,jboolean isLoad)290 static void *findJniFunction(JNIEnv *env, void *handle,
291                                     const char *cname, jboolean isLoad) {
292     const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS;
293     const char *onUnloadSymbols[] = JNI_ONUNLOAD_SYMBOLS;
294     const char **syms;
295     int symsLen;
296     void *entryName = NULL;
297     char *jniFunctionName;
298     int i;
299     size_t len;
300 
301     // Check for JNI_On(Un)Load<_libname> function
302     if (isLoad) {
303         syms = onLoadSymbols;
304         symsLen = sizeof(onLoadSymbols) / sizeof(char *);
305     } else {
306         syms = onUnloadSymbols;
307         symsLen = sizeof(onUnloadSymbols) / sizeof(char *);
308     }
309     for (i = 0; i < symsLen; i++) {
310         // cname + sym + '_' + '\0'
311         if ((len = (cname != NULL ? strlen(cname) : 0) + strlen(syms[i]) + 2) >
312             FILENAME_MAX) {
313             goto done;
314         }
315         jniFunctionName = malloc(len);
316         if (jniFunctionName == NULL) {
317             JNU_ThrowOutOfMemoryError(env, NULL);
318             goto done;
319         }
320         buildJniFunctionName(syms[i], cname, jniFunctionName);
321         entryName = JVM_FindLibraryEntry(handle, jniFunctionName);
322         free(jniFunctionName);
323         if(entryName) {
324             break;
325         }
326     }
327 
328  done:
329     return entryName;
330 }
331 
332 /*
333  * Class:     java_lang_ClassLoader_NativeLibrary
334  * Method:    load0
335  * Signature: (Ljava/lang/String;Z)Z
336  */
337 JNIEXPORT jboolean JNICALL
Java_java_lang_ClassLoader_00024NativeLibrary_load0(JNIEnv * env,jobject this,jstring name,jboolean isBuiltin)338 Java_java_lang_ClassLoader_00024NativeLibrary_load0
339   (JNIEnv *env, jobject this, jstring name, jboolean isBuiltin)
340 {
341     const char *cname;
342     jint jniVersion;
343     jthrowable cause;
344     void * handle;
345     jboolean loaded = JNI_FALSE;
346 
347     if (!initIDs(env))
348         return JNI_FALSE;
349 
350     cname = JNU_GetStringPlatformChars(env, name, 0);
351     if (cname == 0)
352         return JNI_FALSE;
353     handle = isBuiltin ? procHandle : JVM_LoadLibrary(cname);
354     if (handle) {
355         JNI_OnLoad_t JNI_OnLoad;
356         JNI_OnLoad = (JNI_OnLoad_t)findJniFunction(env, handle,
357                                                    isBuiltin ? cname : NULL,
358                                                    JNI_TRUE);
359         if (JNI_OnLoad) {
360             JavaVM *jvm;
361             (*env)->GetJavaVM(env, &jvm);
362             jniVersion = (*JNI_OnLoad)(jvm, NULL);
363         } else {
364             jniVersion = 0x00010001;
365         }
366 
367         cause = (*env)->ExceptionOccurred(env);
368         if (cause) {
369             (*env)->ExceptionClear(env);
370             (*env)->Throw(env, cause);
371             if (!isBuiltin) {
372                 JVM_UnloadLibrary(handle);
373             }
374             goto done;
375         }
376 
377         if (!JVM_IsSupportedJNIVersion(jniVersion) ||
378             (isBuiltin && jniVersion < JNI_VERSION_1_8)) {
379             char msg[256];
380             jio_snprintf(msg, sizeof(msg),
381                          "unsupported JNI version 0x%08X required by %s",
382                          jniVersion, cname);
383             JNU_ThrowByName(env, "java/lang/UnsatisfiedLinkError", msg);
384             if (!isBuiltin) {
385                 JVM_UnloadLibrary(handle);
386             }
387             goto done;
388         }
389         (*env)->SetIntField(env, this, jniVersionID, jniVersion);
390     } else {
391         cause = (*env)->ExceptionOccurred(env);
392         if (cause) {
393             (*env)->ExceptionClear(env);
394             (*env)->SetLongField(env, this, handleID, (jlong)0);
395             (*env)->Throw(env, cause);
396         }
397         goto done;
398     }
399     (*env)->SetLongField(env, this, handleID, ptr_to_jlong(handle));
400     loaded = JNI_TRUE;
401 
402  done:
403     JNU_ReleaseStringPlatformChars(env, name, cname);
404     return loaded;
405 }
406 
407 /*
408  * Class:     java_lang_ClassLoader_NativeLibrary
409  * Method:    unload
410  * Signature: (Ljava/lang/String;ZJ)V
411  */
412 JNIEXPORT void JNICALL
Java_java_lang_ClassLoader_00024NativeLibrary_unload(JNIEnv * env,jclass cls,jstring name,jboolean isBuiltin,jlong address)413 Java_java_lang_ClassLoader_00024NativeLibrary_unload
414 (JNIEnv *env, jclass cls, jstring name, jboolean isBuiltin, jlong address)
415 {
416     const char *onUnloadSymbols[] = JNI_ONUNLOAD_SYMBOLS;
417     void *handle;
418     JNI_OnUnload_t JNI_OnUnload;
419      const char *cname;
420 
421     if (!initIDs(env))
422         return;
423     cname = JNU_GetStringPlatformChars(env, name, 0);
424     if (cname == NULL) {
425         return;
426     }
427     handle = jlong_to_ptr(address);
428     JNI_OnUnload = (JNI_OnUnload_t )findJniFunction(env, handle,
429                                                     isBuiltin ? cname : NULL,
430                                                     JNI_FALSE);
431     if (JNI_OnUnload) {
432         JavaVM *jvm;
433         (*env)->GetJavaVM(env, &jvm);
434         (*JNI_OnUnload)(jvm, NULL);
435     }
436     if (!isBuiltin) {
437         JVM_UnloadLibrary(handle);
438     }
439     JNU_ReleaseStringPlatformChars(env, name, cname);
440 }
441 
442 /*
443  * Class:     java_lang_ClassLoader_NativeLibrary
444  * Method:    findEntry
445  * Signature: (Ljava/lang/String;)J
446  */
447 JNIEXPORT jlong JNICALL
Java_java_lang_ClassLoader_00024NativeLibrary_findEntry(JNIEnv * env,jobject this,jstring name)448 Java_java_lang_ClassLoader_00024NativeLibrary_findEntry
449   (JNIEnv *env, jobject this, jstring name)
450 {
451     jlong handle;
452     const char *cname;
453     jlong res;
454 
455     if (!initIDs(env))
456         return jlong_zero;
457 
458     handle = (*env)->GetLongField(env, this, handleID);
459     cname = (*env)->GetStringUTFChars(env, name, 0);
460     if (cname == 0)
461         return jlong_zero;
462     res = ptr_to_jlong(JVM_FindLibraryEntry(jlong_to_ptr(handle), cname));
463     (*env)->ReleaseStringUTFChars(env, name, cname);
464     return res;
465 }
466 /*
467  * Class:     java_lang_ClassLoader
468  * Method:    findBuiltinLib
469  * Signature: (Ljava/lang/String;)Ljava/lang/String;
470  */
471 JNIEXPORT jstring JNICALL
Java_java_lang_ClassLoader_findBuiltinLib(JNIEnv * env,jclass cls,jstring name)472 Java_java_lang_ClassLoader_findBuiltinLib
473   (JNIEnv *env, jclass cls, jstring name)
474 {
475     const char *cname;
476     char *libName;
477     size_t prefixLen = strlen(JNI_LIB_PREFIX);
478     size_t suffixLen = strlen(JNI_LIB_SUFFIX);
479     size_t len;
480     jstring lib;
481     void *ret;
482     const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS;
483 
484     if (name == NULL) {
485         JNU_ThrowInternalError(env, "NULL filename for native library");
486         return NULL;
487     }
488     procHandle = getProcessHandle();
489     cname = JNU_GetStringPlatformChars(env, name, 0);
490     if (cname == NULL) {
491         return NULL;
492     }
493     // Copy name Skipping PREFIX
494     len = strlen(cname);
495     if (len <= (prefixLen+suffixLen)) {
496         JNU_ReleaseStringPlatformChars(env, name, cname);
497         return NULL;
498     }
499     libName = malloc(len + 1); //+1 for null if prefix+suffix == 0
500     if (libName == NULL) {
501         JNU_ReleaseStringPlatformChars(env, name, cname);
502         JNU_ThrowOutOfMemoryError(env, NULL);
503         return NULL;
504     }
505     if (len > prefixLen) {
506         strcpy(libName, cname+prefixLen);
507     }
508     JNU_ReleaseStringPlatformChars(env, name, cname);
509 
510     // Strip SUFFIX
511     libName[strlen(libName)-suffixLen] = '\0';
512 
513     // Check for JNI_OnLoad_libname function
514     ret = findJniFunction(env, procHandle, libName, JNI_TRUE);
515     if (ret != NULL) {
516         lib = JNU_NewStringPlatform(env, libName);
517         free(libName);
518         return lib;
519     }
520     free(libName);
521     return NULL;
522 }
523