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
  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*
  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
  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
 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 JNIEXPORT jclass JNICALL
 215 Java_java_lang_ClassLoader_defineClass0(JNIEnv *env,
 216                                         jclass cls,
 217                                         jobject loader,
 218                                         jclass lookup,
 219                                         jstring name,
 220                                         jbyteArray data,
 221                                         jint offset,
 222                                         jint length,
 223                                         jobject pd,
 224                                         jint flags,
 225                                         jobject classData)
 226 {
 227     jbyte *body;
 228     char *utfName;
 229     jclass result = 0;
 230     char buf[128];
 231 
 232     if (data == NULL) {
 233         JNU_ThrowNullPointerException(env, 0);
 234         return 0;
 235     }
 236 
 237     /* Work around 4153825. malloc crashes on Solaris when passed a
 238      * negative size.
 239      */
 240     if (length < 0) {
 241         JNU_ThrowArrayIndexOutOfBoundsException(env, 0);
 242         return 0;
 243     }
 244 
 245     body = (jbyte *)malloc(length);
 246     if (body == 0) {
 247         JNU_ThrowOutOfMemoryError(env, 0);
 248         return 0;
 249     }
 250 
 251     (*env)->GetByteArrayRegion(env, data, offset, length, body);
 252 
 253     if ((*env)->ExceptionOccurred(env))
 254         goto free_body;
 255 
 256     if (name != NULL) {
 257         utfName = getUTF(env, name, buf, sizeof(buf));
 258         if (utfName == NULL) {
 259             goto free_body;
 260         }
 261         VerifyFixClassname(utfName);
 262     } else {
 263         utfName = NULL;
 264     }
 265 
 266     return JVM_LookupDefineClass(env, lookup, utfName, loader, body, length, pd, flags, classData);
 267 
 268  free_body:
 269     free(body);
 270     return result;
 271 }
 272 
 273 /*
 274  * Returns NULL if class not found.
 275  */
 276 JNIEXPORT jclass JNICALL
 277 Java_java_lang_ClassLoader_findBootstrapClass(JNIEnv *env, jobject loader,
 278                                               jstring classname)
 279 {
 280     char *clname;
 281     jclass cls = 0;
 282     char buf[128];
 283 
 284     if (classname == NULL) {
 285         return 0;
 286     }
 287 
 288     clname = getUTF(env, classname, buf, sizeof(buf));
 289     if (clname == NULL) {
 290         JNU_ThrowOutOfMemoryError(env, NULL);
 291         return NULL;
 292     }
 293     VerifyFixClassname(clname);
 294 
 295     if (!VerifyClassname(clname, JNI_TRUE)) {  /* expects slashed name */
 296         goto done;
 297     }
 298 
 299     cls = JVM_FindClassFromBootLoader(env, clname);
 300 
 301  done:
 302     if (clname != buf) {
 303         free(clname);
 304     }
 305 
 306     return cls;
 307 }
 308 
 309 JNIEXPORT jclass JNICALL
 310 Java_java_lang_ClassLoader_findLoadedClass0(JNIEnv *env, jobject loader,
 311                                            jstring name)
 312 {
 313     if (name == NULL) {
 314         return 0;
 315     } else {
 316         return JVM_FindLoadedClass(env, loader, name);
 317     }
 318 }
 319 
 320 static jfieldID handleID;
 321 static jfieldID jniVersionID;
 322 static void *procHandle;
 323 
 324 static jboolean initIDs(JNIEnv *env)
 325 {
 326     if (handleID == 0) {
 327         jclass this =
 328             (*env)->FindClass(env, "java/lang/ClassLoader$NativeLibrary");
 329         if (this == 0)
 330             return JNI_FALSE;
 331         handleID = (*env)->GetFieldID(env, this, "handle", "J");
 332         if (handleID == 0)
 333             return JNI_FALSE;
 334         jniVersionID = (*env)->GetFieldID(env, this, "jniVersion", "I");
 335         if (jniVersionID == 0)
 336             return JNI_FALSE;
 337         procHandle = getProcessHandle();
 338     }
 339     return JNI_TRUE;
 340 }
 341 
 342 typedef jint (JNICALL *JNI_OnLoad_t)(JavaVM *, void *);
 343 typedef void (JNICALL *JNI_OnUnload_t)(JavaVM *, void *);
 344 
 345 /*
 346  * Support for finding JNI_On(Un)Load_<lib_name> if it exists.
 347  * If cname == NULL then just find normal JNI_On(Un)Load entry point
 348  */
 349 static void *findJniFunction(JNIEnv *env, void *handle,
 350                                     const char *cname, jboolean isLoad) {
 351     const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS;
 352     const char *onUnloadSymbols[] = JNI_ONUNLOAD_SYMBOLS;
 353     const char **syms;
 354     int symsLen;
 355     void *entryName = NULL;
 356     char *jniFunctionName;
 357     int i;
 358     size_t len;
 359 
 360     // Check for JNI_On(Un)Load<_libname> function
 361     if (isLoad) {
 362         syms = onLoadSymbols;
 363         symsLen = sizeof(onLoadSymbols) / sizeof(char *);
 364     } else {
 365         syms = onUnloadSymbols;
 366         symsLen = sizeof(onUnloadSymbols) / sizeof(char *);
 367     }
 368     for (i = 0; i < symsLen; i++) {
 369         // cname + sym + '_' + '\0'
 370         if ((len = (cname != NULL ? strlen(cname) : 0) + strlen(syms[i]) + 2) >
 371             FILENAME_MAX) {
 372             goto done;
 373         }
 374         jniFunctionName = malloc(len);
 375         if (jniFunctionName == NULL) {
 376             JNU_ThrowOutOfMemoryError(env, NULL);
 377             goto done;
 378         }
 379         buildJniFunctionName(syms[i], cname, jniFunctionName);
 380         entryName = JVM_FindLibraryEntry(handle, jniFunctionName);
 381         free(jniFunctionName);
 382         if(entryName) {
 383             break;
 384         }
 385     }
 386 
 387  done:
 388     return entryName;
 389 }
 390 
 391 /*
 392  * Class:     java_lang_ClassLoader_NativeLibrary
 393  * Method:    load0
 394  * Signature: (Ljava/lang/String;Z)Z
 395  */
 396 JNIEXPORT jboolean JNICALL
 397 Java_java_lang_ClassLoader_00024NativeLibrary_load0
 398   (JNIEnv *env, jobject this, jstring name, jboolean isBuiltin)
 399 {
 400     const char *cname;
 401     jint jniVersion;
 402     jthrowable cause;
 403     void * handle;
 404     jboolean loaded = JNI_FALSE;
 405 
 406     if (!initIDs(env))
 407         return JNI_FALSE;
 408 
 409     cname = JNU_GetStringPlatformChars(env, name, 0);
 410     if (cname == 0)
 411         return JNI_FALSE;
 412     handle = isBuiltin ? procHandle : JVM_LoadLibrary(cname);
 413     if (handle) {
 414         JNI_OnLoad_t JNI_OnLoad;
 415         JNI_OnLoad = (JNI_OnLoad_t)findJniFunction(env, handle,
 416                                                    isBuiltin ? cname : NULL,
 417                                                    JNI_TRUE);
 418         if (JNI_OnLoad) {
 419             JavaVM *jvm;
 420             (*env)->GetJavaVM(env, &jvm);
 421             jniVersion = (*JNI_OnLoad)(jvm, NULL);
 422         } else {
 423             jniVersion = 0x00010001;
 424         }
 425 
 426         cause = (*env)->ExceptionOccurred(env);
 427         if (cause) {
 428             (*env)->ExceptionClear(env);
 429             (*env)->Throw(env, cause);
 430             if (!isBuiltin) {
 431                 JVM_UnloadLibrary(handle);
 432             }
 433             goto done;
 434         }
 435 
 436         if (!JVM_IsSupportedJNIVersion(jniVersion) ||
 437             (isBuiltin && jniVersion < JNI_VERSION_1_8)) {
 438             char msg[256];
 439             jio_snprintf(msg, sizeof(msg),
 440                          "unsupported JNI version 0x%08X required by %s",
 441                          jniVersion, cname);
 442             JNU_ThrowByName(env, "java/lang/UnsatisfiedLinkError", msg);
 443             if (!isBuiltin) {
 444                 JVM_UnloadLibrary(handle);
 445             }
 446             goto done;
 447         }
 448         (*env)->SetIntField(env, this, jniVersionID, jniVersion);
 449     } else {
 450         cause = (*env)->ExceptionOccurred(env);
 451         if (cause) {
 452             (*env)->ExceptionClear(env);
 453             (*env)->SetLongField(env, this, handleID, (jlong)0);
 454             (*env)->Throw(env, cause);
 455         }
 456         goto done;
 457     }
 458     (*env)->SetLongField(env, this, handleID, ptr_to_jlong(handle));
 459     loaded = JNI_TRUE;
 460 
 461  done:
 462     JNU_ReleaseStringPlatformChars(env, name, cname);
 463     return loaded;
 464 }
 465 
 466 /*
 467  * Class:     java_lang_ClassLoader_NativeLibrary
 468  * Method:    unload
 469  * Signature: (Ljava/lang/String;ZJ)V
 470  */
 471 JNIEXPORT void JNICALL
 472 Java_java_lang_ClassLoader_00024NativeLibrary_unload
 473 (JNIEnv *env, jclass cls, jstring name, jboolean isBuiltin, jlong address)
 474 {
 475     const char *onUnloadSymbols[] = JNI_ONUNLOAD_SYMBOLS;
 476     void *handle;
 477     JNI_OnUnload_t JNI_OnUnload;
 478      const char *cname;
 479 
 480     if (!initIDs(env))
 481         return;
 482     cname = JNU_GetStringPlatformChars(env, name, 0);
 483     if (cname == NULL) {
 484         return;
 485     }
 486     handle = jlong_to_ptr(address);
 487     JNI_OnUnload = (JNI_OnUnload_t )findJniFunction(env, handle,
 488                                                     isBuiltin ? cname : NULL,
 489                                                     JNI_FALSE);
 490     if (JNI_OnUnload) {
 491         JavaVM *jvm;
 492         (*env)->GetJavaVM(env, &jvm);
 493         (*JNI_OnUnload)(jvm, NULL);
 494     }
 495     if (!isBuiltin) {
 496         JVM_UnloadLibrary(handle);
 497     }
 498     JNU_ReleaseStringPlatformChars(env, name, cname);
 499 }
 500 
 501 /*
 502  * Class:     java_lang_ClassLoader_NativeLibrary
 503  * Method:    findEntry
 504  * Signature: (Ljava/lang/String;)J
 505  */
 506 JNIEXPORT jlong JNICALL
 507 Java_java_lang_ClassLoader_00024NativeLibrary_findEntry
 508   (JNIEnv *env, jobject this, jstring name)
 509 {
 510     jlong handle;
 511     const char *cname;
 512     jlong res;
 513 
 514     if (!initIDs(env))
 515         return jlong_zero;
 516 
 517     handle = (*env)->GetLongField(env, this, handleID);
 518     cname = (*env)->GetStringUTFChars(env, name, 0);
 519     if (cname == 0)
 520         return jlong_zero;
 521     res = ptr_to_jlong(JVM_FindLibraryEntry(jlong_to_ptr(handle), cname));
 522     (*env)->ReleaseStringUTFChars(env, name, cname);
 523     return res;
 524 }
 525 /*
 526  * Class:     java_lang_ClassLoader
 527  * Method:    findBuiltinLib
 528  * Signature: (Ljava/lang/String;)Ljava/lang/String;
 529  */
 530 JNIEXPORT jstring JNICALL
 531 Java_java_lang_ClassLoader_findBuiltinLib
 532   (JNIEnv *env, jclass cls, jstring name)
 533 {
 534     const char *cname;
 535     char *libName;
 536     size_t prefixLen = strlen(JNI_LIB_PREFIX);
 537     size_t suffixLen = strlen(JNI_LIB_SUFFIX);
 538     size_t len;
 539     jstring lib;
 540     void *ret;
 541     const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS;
 542 
 543     if (name == NULL) {
 544         JNU_ThrowInternalError(env, "NULL filename for native library");
 545         return NULL;
 546     }
 547     procHandle = getProcessHandle();
 548     cname = JNU_GetStringPlatformChars(env, name, 0);
 549     if (cname == NULL) {
 550         return NULL;
 551     }
 552     // Copy name Skipping PREFIX
 553     len = strlen(cname);
 554     if (len <= (prefixLen+suffixLen)) {
 555         JNU_ReleaseStringPlatformChars(env, name, cname);
 556         return NULL;
 557     }
 558     libName = malloc(len + 1); //+1 for null if prefix+suffix == 0
 559     if (libName == NULL) {
 560         JNU_ReleaseStringPlatformChars(env, name, cname);
 561         JNU_ThrowOutOfMemoryError(env, NULL);
 562         return NULL;
 563     }
 564     if (len > prefixLen) {
 565         strcpy(libName, cname+prefixLen);
 566     }
 567     JNU_ReleaseStringPlatformChars(env, name, cname);
 568 
 569     // Strip SUFFIX
 570     libName[strlen(libName)-suffixLen] = '\0';
 571 
 572     // Check for JNI_OnLoad_libname function
 573     ret = findJniFunction(env, procHandle, libName, JNI_TRUE);
 574     if (ret != NULL) {
 575         lib = JNU_NewStringPlatform(env, libName);
 576         free(libName);
 577         return lib;
 578     }
 579     free(libName);
 580     return NULL;
 581 }