1 /* 2 * Copyright (c) 2015, 2018, 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 package jdk.internal.loader; 27 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.lang.module.ModuleDescriptor; 31 import java.lang.module.ModuleReference; 32 import java.lang.module.ModuleReader; 33 import java.lang.ref.SoftReference; 34 import java.net.MalformedURLException; 35 import java.net.URI; 36 import java.net.URL; 37 import java.nio.ByteBuffer; 38 import java.security.AccessController; 39 import java.security.CodeSigner; 40 import java.security.CodeSource; 41 import java.security.PermissionCollection; 42 import java.security.PrivilegedAction; 43 import java.security.PrivilegedActionException; 44 import java.security.PrivilegedExceptionAction; 45 import java.security.SecureClassLoader; 46 import java.util.ArrayList; 47 import java.util.Collections; 48 import java.util.Enumeration; 49 import java.util.Iterator; 50 import java.util.List; 51 import java.util.Map; 52 import java.util.NoSuchElementException; 53 import java.util.Optional; 54 import java.util.concurrent.ConcurrentHashMap; 55 import java.util.function.Function; 56 import java.util.jar.Attributes; 57 import java.util.jar.Manifest; 58 import java.util.stream.Stream; 59 60 import jdk.internal.misc.SharedSecrets; 61 import jdk.internal.misc.VM; 62 import jdk.internal.module.ModulePatcher.PatchedModuleReader; 63 import jdk.internal.module.Resources; 64 import sun.security.util.LazyCodeSourcePermissionCollection; 65 66 67 /** 68 * The platform or application class loader. Resources loaded from modules 69 * defined to the boot class loader are also loaded via an instance of this 70 * ClassLoader type. 71 * 72 * <p> This ClassLoader supports loading of classes and resources from modules. 73 * Modules are defined to the ClassLoader by invoking the {@link #loadModule} 74 * method. Defining a module to this ClassLoader has the effect of making the 75 * types in the module visible. </p> 76 * 77 * <p> This ClassLoader also supports loading of classes and resources from a 78 * class path of URLs that are specified to the ClassLoader at construction 79 * time. The class path may expand at runtime (the Class-Path attribute in JAR 80 * files or via instrumentation agents). </p> 81 * 82 * <p> The delegation model used by this ClassLoader differs to the regular 83 * delegation model. When requested to load a class then this ClassLoader first 84 * maps the class name to its package name. If there is a module defined to a 85 * BuiltinClassLoader containing this package then the class loader delegates 86 * directly to that class loader. If there isn't a module containing the 87 * package then it delegates the search to the parent class loader and if not 88 * found in the parent then it searches the class path. The main difference 89 * between this and the usual delegation model is that it allows the platform 90 * class loader to delegate to the application class loader, important with 91 * upgraded modules defined to the platform class loader. 92 */ 93 94 public class BuiltinClassLoader 95 extends SecureClassLoader 96 { 97 static { 98 if (!ClassLoader.registerAsParallelCapable()) 99 throw new InternalError("Unable to register as parallel capable"); 100 } 101 102 // parent ClassLoader 103 private final BuiltinClassLoader parent; 104 105 // the URL class path, or null if there is no class path 106 private final URLClassPath ucp; 107 108 109 /** 110 * A module defined/loaded by a built-in class loader. 111 * 112 * A LoadedModule encapsulates a ModuleReference along with its CodeSource 113 * URL to avoid needing to create this URL when defining classes. 114 */ 115 private static class LoadedModule { 116 private final BuiltinClassLoader loader; 117 private final ModuleReference mref; 118 private final URL codeSourceURL; // may be null 119 LoadedModule(BuiltinClassLoader loader, ModuleReference mref)120 LoadedModule(BuiltinClassLoader loader, ModuleReference mref) { 121 URL url = null; 122 if (mref.location().isPresent()) { 123 try { 124 url = mref.location().get().toURL(); 125 } catch (MalformedURLException | IllegalArgumentException e) { } 126 } 127 this.loader = loader; 128 this.mref = mref; 129 this.codeSourceURL = url; 130 } 131 loader()132 BuiltinClassLoader loader() { return loader; } mref()133 ModuleReference mref() { return mref; } name()134 String name() { return mref.descriptor().name(); } codeSourceURL()135 URL codeSourceURL() { return codeSourceURL; } 136 } 137 138 139 // maps package name to loaded module for modules in the boot layer 140 private static final Map<String, LoadedModule> packageToModule 141 = new ConcurrentHashMap<>(1024); 142 143 // maps a module name to a module reference 144 private final Map<String, ModuleReference> nameToModule; 145 146 // maps a module reference to a module reader 147 private final Map<ModuleReference, ModuleReader> moduleToReader; 148 149 // cache of resource name -> list of URLs. 150 // used only for resources that are not in module packages 151 private volatile SoftReference<Map<String, List<URL>>> resourceCache; 152 153 /** 154 * Create a new instance. 155 */ BuiltinClassLoader(String name, BuiltinClassLoader parent, URLClassPath ucp)156 BuiltinClassLoader(String name, BuiltinClassLoader parent, URLClassPath ucp) { 157 // ensure getParent() returns null when the parent is the boot loader 158 super(name, parent == null || parent == ClassLoaders.bootLoader() ? null : parent); 159 160 this.parent = parent; 161 this.ucp = ucp; 162 163 this.nameToModule = new ConcurrentHashMap<>(); 164 this.moduleToReader = new ConcurrentHashMap<>(); 165 } 166 167 /** 168 * Returns {@code true} if there is a class path associated with this 169 * class loader. 170 */ hasClassPath()171 boolean hasClassPath() { 172 return ucp != null; 173 } 174 175 /** 176 * Register a module this class loader. This has the effect of making the 177 * types in the module visible. 178 */ loadModule(ModuleReference mref)179 public void loadModule(ModuleReference mref) { 180 String mn = mref.descriptor().name(); 181 if (nameToModule.putIfAbsent(mn, mref) != null) { 182 throw new InternalError(mn + " already defined to this loader"); 183 } 184 185 LoadedModule loadedModule = new LoadedModule(this, mref); 186 for (String pn : mref.descriptor().packages()) { 187 LoadedModule other = packageToModule.putIfAbsent(pn, loadedModule); 188 if (other != null) { 189 throw new InternalError(pn + " in modules " + mn + " and " 190 + other.mref().descriptor().name()); 191 } 192 } 193 194 // clear resources cache if VM is already initialized 195 if (VM.isModuleSystemInited() && resourceCache != null) { 196 resourceCache = null; 197 } 198 } 199 200 /** 201 * Returns the {@code ModuleReference} for the named module defined to 202 * this class loader; or {@code null} if not defined. 203 * 204 * @param name The name of the module to find 205 */ findModule(String name)206 protected ModuleReference findModule(String name) { 207 return nameToModule.get(name); 208 } 209 210 211 // -- finding resources 212 213 /** 214 * Returns a URL to a resource of the given name in a module defined to 215 * this class loader. 216 */ 217 @Override findResource(String mn, String name)218 public URL findResource(String mn, String name) throws IOException { 219 URL url = null; 220 221 if (mn != null) { 222 // find in module 223 ModuleReference mref = nameToModule.get(mn); 224 if (mref != null) { 225 url = findResource(mref, name); 226 } 227 } else { 228 // find on class path 229 url = findResourceOnClassPath(name); 230 } 231 232 return checkURL(url); // check access before returning 233 } 234 235 /** 236 * Returns an input stream to a resource of the given name in a module 237 * defined to this class loader. 238 */ findResourceAsStream(String mn, String name)239 public InputStream findResourceAsStream(String mn, String name) 240 throws IOException 241 { 242 // Need URL to resource when running with a security manager so that 243 // the right permission check is done. 244 if (System.getSecurityManager() != null || mn == null) { 245 URL url = findResource(mn, name); 246 return (url != null) ? url.openStream() : null; 247 } 248 249 // find in module defined to this loader, no security manager 250 ModuleReference mref = nameToModule.get(mn); 251 if (mref != null) { 252 return moduleReaderFor(mref).open(name).orElse(null); 253 } else { 254 return null; 255 } 256 } 257 258 /** 259 * Finds a resource with the given name in the modules defined to this 260 * class loader or its class path. 261 */ 262 @Override findResource(String name)263 public URL findResource(String name) { 264 String pn = Resources.toPackageName(name); 265 LoadedModule module = packageToModule.get(pn); 266 if (module != null) { 267 268 // resource is in a package of a module defined to this loader 269 if (module.loader() == this) { 270 URL url; 271 try { 272 url = findResource(module.name(), name); // checks URL 273 } catch (IOException ioe) { 274 return null; 275 } 276 if (url != null 277 && (name.endsWith(".class") 278 || url.toString().endsWith("/") 279 || isOpen(module.mref(), pn))) { 280 return url; 281 } 282 } 283 284 } else { 285 286 // not in a module package but may be in module defined to this loader 287 try { 288 List<URL> urls = findMiscResource(name); 289 if (!urls.isEmpty()) { 290 URL url = urls.get(0); 291 if (url != null) { 292 return checkURL(url); // check access before returning 293 } 294 } 295 } catch (IOException ioe) { 296 return null; 297 } 298 299 } 300 301 // search class path 302 URL url = findResourceOnClassPath(name); 303 return checkURL(url); 304 } 305 306 /** 307 * Returns an enumeration of URL objects to all the resources with the 308 * given name in modules defined to this class loader or on the class 309 * path of this loader. 310 */ 311 @Override findResources(String name)312 public Enumeration<URL> findResources(String name) throws IOException { 313 List<URL> checked = new ArrayList<>(); // list of checked URLs 314 315 String pn = Resources.toPackageName(name); 316 LoadedModule module = packageToModule.get(pn); 317 if (module != null) { 318 319 // resource is in a package of a module defined to this loader 320 if (module.loader() == this) { 321 URL url = findResource(module.name(), name); // checks URL 322 if (url != null 323 && (name.endsWith(".class") 324 || url.toString().endsWith("/") 325 || isOpen(module.mref(), pn))) { 326 checked.add(url); 327 } 328 } 329 330 } else { 331 // not in a package of a module defined to this loader 332 for (URL url : findMiscResource(name)) { 333 url = checkURL(url); 334 if (url != null) { 335 checked.add(url); 336 } 337 } 338 } 339 340 // class path (not checked) 341 Enumeration<URL> e = findResourcesOnClassPath(name); 342 343 // concat the checked URLs and the (not checked) class path 344 return new Enumeration<>() { 345 final Iterator<URL> iterator = checked.iterator(); 346 URL next; 347 private boolean hasNext() { 348 if (next != null) { 349 return true; 350 } else if (iterator.hasNext()) { 351 next = iterator.next(); 352 return true; 353 } else { 354 // need to check each URL 355 while (e.hasMoreElements() && next == null) { 356 next = checkURL(e.nextElement()); 357 } 358 return next != null; 359 } 360 } 361 @Override 362 public boolean hasMoreElements() { 363 return hasNext(); 364 } 365 @Override 366 public URL nextElement() { 367 if (hasNext()) { 368 URL result = next; 369 next = null; 370 return result; 371 } else { 372 throw new NoSuchElementException(); 373 } 374 } 375 }; 376 377 } 378 379 /** 380 * Returns the list of URLs to a "miscellaneous" resource in modules 381 * defined to this loader. A miscellaneous resource is not in a module 382 * package, e.g. META-INF/services/p.S. 383 * 384 * The cache used by this method avoids repeated searching of all modules. 385 */ findMiscResource(String name)386 private List<URL> findMiscResource(String name) throws IOException { 387 SoftReference<Map<String, List<URL>>> ref = this.resourceCache; 388 Map<String, List<URL>> map = (ref != null) ? ref.get() : null; 389 if (map == null) { 390 map = new ConcurrentHashMap<>(); 391 this.resourceCache = new SoftReference<>(map); 392 } else { 393 List<URL> urls = map.get(name); 394 if (urls != null) 395 return urls; 396 } 397 398 // search all modules for the resource 399 List<URL> urls; 400 try { 401 urls = AccessController.doPrivileged( 402 new PrivilegedExceptionAction<>() { 403 @Override 404 public List<URL> run() throws IOException { 405 List<URL> result = null; 406 for (ModuleReference mref : nameToModule.values()) { 407 URI u = moduleReaderFor(mref).find(name).orElse(null); 408 if (u != null) { 409 try { 410 if (result == null) 411 result = new ArrayList<>(); 412 result.add(u.toURL()); 413 } catch (MalformedURLException | 414 IllegalArgumentException e) { 415 } 416 } 417 } 418 return (result != null) ? result : Collections.emptyList(); 419 } 420 }); 421 } catch (PrivilegedActionException pae) { 422 throw (IOException) pae.getCause(); 423 } 424 425 // only cache resources after VM is fully initialized 426 if (VM.isModuleSystemInited()) { 427 map.putIfAbsent(name, urls); 428 } 429 430 return urls; 431 } 432 433 /** 434 * Returns the URL to a resource in a module or {@code null} if not found. 435 */ findResource(ModuleReference mref, String name)436 private URL findResource(ModuleReference mref, String name) throws IOException { 437 URI u; 438 if (System.getSecurityManager() == null) { 439 u = moduleReaderFor(mref).find(name).orElse(null); 440 } else { 441 try { 442 u = AccessController.doPrivileged(new PrivilegedExceptionAction<> () { 443 @Override 444 public URI run() throws IOException { 445 return moduleReaderFor(mref).find(name).orElse(null); 446 } 447 }); 448 } catch (PrivilegedActionException pae) { 449 throw (IOException) pae.getCause(); 450 } 451 } 452 if (u != null) { 453 try { 454 return u.toURL(); 455 } catch (MalformedURLException | IllegalArgumentException e) { } 456 } 457 return null; 458 } 459 460 /** 461 * Returns the URL to a resource in a module. Returns {@code null} if not found 462 * or an I/O error occurs. 463 */ findResourceOrNull(ModuleReference mref, String name)464 private URL findResourceOrNull(ModuleReference mref, String name) { 465 try { 466 return findResource(mref, name); 467 } catch (IOException ignore) { 468 return null; 469 } 470 } 471 472 /** 473 * Returns a URL to a resource on the class path. 474 */ findResourceOnClassPath(String name)475 private URL findResourceOnClassPath(String name) { 476 if (hasClassPath()) { 477 if (System.getSecurityManager() == null) { 478 return ucp.findResource(name, false); 479 } else { 480 PrivilegedAction<URL> pa = () -> ucp.findResource(name, false); 481 return AccessController.doPrivileged(pa); 482 } 483 } else { 484 // no class path 485 return null; 486 } 487 } 488 489 /** 490 * Returns the URLs of all resources of the given name on the class path. 491 */ findResourcesOnClassPath(String name)492 private Enumeration<URL> findResourcesOnClassPath(String name) { 493 if (hasClassPath()) { 494 if (System.getSecurityManager() == null) { 495 return ucp.findResources(name, false); 496 } else { 497 PrivilegedAction<Enumeration<URL>> pa; 498 pa = () -> ucp.findResources(name, false); 499 return AccessController.doPrivileged(pa); 500 } 501 } else { 502 // no class path 503 return Collections.emptyEnumeration(); 504 } 505 } 506 507 // -- finding/loading classes 508 509 /** 510 * Finds the class with the specified binary name. 511 */ 512 @Override findClass(String cn)513 protected Class<?> findClass(String cn) throws ClassNotFoundException { 514 // no class loading until VM is fully initialized 515 if (!VM.isModuleSystemInited()) 516 throw new ClassNotFoundException(cn); 517 518 // find the candidate module for this class 519 LoadedModule loadedModule = findLoadedModule(cn); 520 521 Class<?> c = null; 522 if (loadedModule != null) { 523 524 // attempt to load class in module defined to this loader 525 if (loadedModule.loader() == this) { 526 c = findClassInModuleOrNull(loadedModule, cn); 527 } 528 529 } else { 530 531 // search class path 532 if (hasClassPath()) { 533 c = findClassOnClassPathOrNull(cn); 534 } 535 536 } 537 538 // not found 539 if (c == null) 540 throw new ClassNotFoundException(cn); 541 542 return c; 543 } 544 545 /** 546 * Finds the class with the specified binary name in a module. 547 * This method returns {@code null} if the class cannot be found 548 * or not defined in the specified module. 549 */ 550 @Override findClass(String mn, String cn)551 protected Class<?> findClass(String mn, String cn) { 552 if (mn != null) { 553 // find the candidate module for this class 554 LoadedModule loadedModule = findLoadedModule(mn, cn); 555 if (loadedModule == null) { 556 return null; 557 } 558 559 // attempt to load class in module defined to this loader 560 assert loadedModule.loader() == this; 561 return findClassInModuleOrNull(loadedModule, cn); 562 } 563 564 // search class path 565 if (hasClassPath()) { 566 return findClassOnClassPathOrNull(cn); 567 } 568 569 return null; 570 } 571 572 /** 573 * Loads the class with the specified binary name. 574 */ 575 @Override loadClass(String cn, boolean resolve)576 protected Class<?> loadClass(String cn, boolean resolve) 577 throws ClassNotFoundException 578 { 579 Class<?> c = loadClassOrNull(cn, resolve); 580 if (c == null) 581 throw new ClassNotFoundException(cn); 582 return c; 583 } 584 585 /** 586 * A variation of {@code loadClass} to load a class with the specified 587 * binary name. This method returns {@code null} when the class is not 588 * found. 589 */ loadClassOrNull(String cn, boolean resolve)590 protected Class<?> loadClassOrNull(String cn, boolean resolve) { 591 synchronized (getClassLoadingLock(cn)) { 592 // check if already loaded 593 Class<?> c = findLoadedClass(cn); 594 595 if (c == null) { 596 597 // find the candidate module for this class 598 LoadedModule loadedModule = findLoadedModule(cn); 599 if (loadedModule != null) { 600 601 // package is in a module 602 BuiltinClassLoader loader = loadedModule.loader(); 603 if (loader == this) { 604 if (VM.isModuleSystemInited()) { 605 c = findClassInModuleOrNull(loadedModule, cn); 606 } 607 } else { 608 // delegate to the other loader 609 c = loader.loadClassOrNull(cn); 610 } 611 612 } else { 613 614 // check parent 615 if (parent != null) { 616 c = parent.loadClassOrNull(cn); 617 } 618 619 // check class path 620 if (c == null && hasClassPath() && VM.isModuleSystemInited()) { 621 c = findClassOnClassPathOrNull(cn); 622 } 623 } 624 625 } 626 627 if (resolve && c != null) 628 resolveClass(c); 629 630 return c; 631 } 632 } 633 634 /** 635 * A variation of {@code loadClass} to load a class with the specified 636 * binary name. This method returns {@code null} when the class is not 637 * found. 638 */ loadClassOrNull(String cn)639 protected Class<?> loadClassOrNull(String cn) { 640 return loadClassOrNull(cn, false); 641 } 642 643 /** 644 * Finds the candidate loaded module for the given class name. 645 * Returns {@code null} if none of the modules defined to this 646 * class loader contain the API package for the class. 647 */ findLoadedModule(String cn)648 private LoadedModule findLoadedModule(String cn) { 649 int pos = cn.lastIndexOf('.'); 650 if (pos < 0) 651 return null; // unnamed package 652 653 String pn = cn.substring(0, pos); 654 return packageToModule.get(pn); 655 } 656 657 /** 658 * Finds the candidate loaded module for the given class name 659 * in the named module. Returns {@code null} if the named module 660 * is not defined to this class loader or does not contain 661 * the API package for the class. 662 */ findLoadedModule(String mn, String cn)663 private LoadedModule findLoadedModule(String mn, String cn) { 664 LoadedModule loadedModule = findLoadedModule(cn); 665 if (loadedModule != null && mn.equals(loadedModule.name())) { 666 return loadedModule; 667 } else { 668 return null; 669 } 670 } 671 672 /** 673 * Finds the class with the specified binary name if in a module 674 * defined to this ClassLoader. 675 * 676 * @return the resulting Class or {@code null} if not found 677 */ findClassInModuleOrNull(LoadedModule loadedModule, String cn)678 private Class<?> findClassInModuleOrNull(LoadedModule loadedModule, String cn) { 679 if (System.getSecurityManager() == null) { 680 return defineClass(cn, loadedModule); 681 } else { 682 PrivilegedAction<Class<?>> pa = () -> defineClass(cn, loadedModule); 683 return AccessController.doPrivileged(pa); 684 } 685 } 686 687 /** 688 * Finds the class with the specified binary name on the class path. 689 * 690 * @return the resulting Class or {@code null} if not found 691 */ findClassOnClassPathOrNull(String cn)692 private Class<?> findClassOnClassPathOrNull(String cn) { 693 String path = cn.replace('.', '/').concat(".class"); 694 if (System.getSecurityManager() == null) { 695 Resource res = ucp.getResource(path, false); 696 if (res != null) { 697 try { 698 return defineClass(cn, res); 699 } catch (IOException ioe) { 700 // TBD on how I/O errors should be propagated 701 } 702 } 703 return null; 704 } else { 705 // avoid use of lambda here 706 PrivilegedAction<Class<?>> pa = new PrivilegedAction<>() { 707 public Class<?> run() { 708 Resource res = ucp.getResource(path, false); 709 if (res != null) { 710 try { 711 return defineClass(cn, res); 712 } catch (IOException ioe) { 713 // TBD on how I/O errors should be propagated 714 } 715 } 716 return null; 717 } 718 }; 719 return AccessController.doPrivileged(pa); 720 } 721 } 722 723 /** 724 * Defines the given binary class name to the VM, loading the class 725 * bytes from the given module. 726 * 727 * @return the resulting Class or {@code null} if an I/O error occurs 728 */ defineClass(String cn, LoadedModule loadedModule)729 private Class<?> defineClass(String cn, LoadedModule loadedModule) { 730 ModuleReference mref = loadedModule.mref(); 731 ModuleReader reader = moduleReaderFor(mref); 732 733 try { 734 ByteBuffer bb = null; 735 URL csURL = null; 736 737 // locate class file, special handling for patched modules to 738 // avoid locating the resource twice 739 String rn = cn.replace('.', '/').concat(".class"); 740 if (reader instanceof PatchedModuleReader) { 741 Resource r = ((PatchedModuleReader)reader).findResource(rn); 742 if (r != null) { 743 bb = r.getByteBuffer(); 744 csURL = r.getCodeSourceURL(); 745 } 746 } else { 747 bb = reader.read(rn).orElse(null); 748 csURL = loadedModule.codeSourceURL(); 749 } 750 751 if (bb == null) { 752 // class not found 753 return null; 754 } 755 756 CodeSource cs = new CodeSource(csURL, (CodeSigner[]) null); 757 try { 758 // define class to VM 759 return defineClass(cn, bb, cs); 760 761 } finally { 762 reader.release(bb); 763 } 764 765 } catch (IOException ioe) { 766 // TBD on how I/O errors should be propagated 767 return null; 768 } 769 } 770 771 /** 772 * Defines the given binary class name to the VM, loading the class 773 * bytes via the given Resource object. 774 * 775 * @return the resulting Class 776 * @throws IOException if reading the resource fails 777 * @throws SecurityException if there is a sealing violation (JAR spec) 778 */ defineClass(String cn, Resource res)779 private Class<?> defineClass(String cn, Resource res) throws IOException { 780 URL url = res.getCodeSourceURL(); 781 782 // if class is in a named package then ensure that the package is defined 783 int pos = cn.lastIndexOf('.'); 784 if (pos != -1) { 785 String pn = cn.substring(0, pos); 786 Manifest man = res.getManifest(); 787 defineOrCheckPackage(pn, man, url); 788 } 789 790 // defines the class to the runtime 791 ByteBuffer bb = res.getByteBuffer(); 792 if (bb != null) { 793 CodeSigner[] signers = res.getCodeSigners(); 794 CodeSource cs = new CodeSource(url, signers); 795 return defineClass(cn, bb, cs); 796 } else { 797 byte[] b = res.getBytes(); 798 CodeSigner[] signers = res.getCodeSigners(); 799 CodeSource cs = new CodeSource(url, signers); 800 return defineClass(cn, b, 0, b.length, cs); 801 } 802 } 803 804 805 // -- packages 806 807 /** 808 * Defines a package in this ClassLoader. If the package is already defined 809 * then its sealing needs to be checked if sealed by the legacy sealing 810 * mechanism. 811 * 812 * @throws SecurityException if there is a sealing violation (JAR spec) 813 */ defineOrCheckPackage(String pn, Manifest man, URL url)814 protected Package defineOrCheckPackage(String pn, Manifest man, URL url) { 815 Package pkg = getAndVerifyPackage(pn, man, url); 816 if (pkg == null) { 817 try { 818 if (man != null) { 819 pkg = definePackage(pn, man, url); 820 } else { 821 pkg = definePackage(pn, null, null, null, null, null, null, null); 822 } 823 } catch (IllegalArgumentException iae) { 824 // defined by another thread so need to re-verify 825 pkg = getAndVerifyPackage(pn, man, url); 826 if (pkg == null) 827 throw new InternalError("Cannot find package: " + pn); 828 } 829 } 830 return pkg; 831 } 832 833 /** 834 * Gets the Package with the specified package name. If defined 835 * then verifies it against the manifest and code source. 836 * 837 * @throws SecurityException if there is a sealing violation (JAR spec) 838 */ getAndVerifyPackage(String pn, Manifest man, URL url)839 private Package getAndVerifyPackage(String pn, Manifest man, URL url) { 840 Package pkg = getDefinedPackage(pn); 841 if (pkg != null) { 842 if (pkg.isSealed()) { 843 if (!pkg.isSealed(url)) { 844 throw new SecurityException( 845 "sealing violation: package " + pn + " is sealed"); 846 } 847 } else { 848 // can't seal package if already defined without sealing 849 if ((man != null) && isSealed(pn, man)) { 850 throw new SecurityException( 851 "sealing violation: can't seal package " + pn + 852 ": already defined"); 853 } 854 } 855 } 856 return pkg; 857 } 858 859 /** 860 * Defines a new package in this ClassLoader. The attributes in the specified 861 * Manifest are used to get the package version and sealing information. 862 * 863 * @throws IllegalArgumentException if the package name duplicates an 864 * existing package either in this class loader or one of its ancestors 865 * @throws SecurityException if the package name is untrusted in the manifest 866 */ definePackage(String pn, Manifest man, URL url)867 private Package definePackage(String pn, Manifest man, URL url) { 868 String specTitle = null; 869 String specVersion = null; 870 String specVendor = null; 871 String implTitle = null; 872 String implVersion = null; 873 String implVendor = null; 874 String sealed = null; 875 URL sealBase = null; 876 877 if (man != null) { 878 Attributes attr = SharedSecrets.javaUtilJarAccess() 879 .getTrustedAttributes(man, pn.replace('.', '/').concat("/")); 880 if (attr != null) { 881 specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE); 882 specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION); 883 specVendor = attr.getValue(Attributes.Name.SPECIFICATION_VENDOR); 884 implTitle = attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE); 885 implVersion = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION); 886 implVendor = attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR); 887 sealed = attr.getValue(Attributes.Name.SEALED); 888 } 889 890 attr = man.getMainAttributes(); 891 if (attr != null) { 892 if (specTitle == null) 893 specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE); 894 if (specVersion == null) 895 specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION); 896 if (specVendor == null) 897 specVendor = attr.getValue(Attributes.Name.SPECIFICATION_VENDOR); 898 if (implTitle == null) 899 implTitle = attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE); 900 if (implVersion == null) 901 implVersion = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION); 902 if (implVendor == null) 903 implVendor = attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR); 904 if (sealed == null) 905 sealed = attr.getValue(Attributes.Name.SEALED); 906 } 907 908 // package is sealed 909 if ("true".equalsIgnoreCase(sealed)) 910 sealBase = url; 911 } 912 return definePackage(pn, 913 specTitle, 914 specVersion, 915 specVendor, 916 implTitle, 917 implVersion, 918 implVendor, 919 sealBase); 920 } 921 922 /** 923 * Returns {@code true} if the specified package name is sealed according to 924 * the given manifest. 925 * 926 * @throws SecurityException if the package name is untrusted in the manifest 927 */ isSealed(String pn, Manifest man)928 private boolean isSealed(String pn, Manifest man) { 929 Attributes attr = SharedSecrets.javaUtilJarAccess() 930 .getTrustedAttributes(man, pn.replace('.', '/').concat("/")); 931 String sealed = null; 932 if (attr != null) 933 sealed = attr.getValue(Attributes.Name.SEALED); 934 if (sealed == null && (attr = man.getMainAttributes()) != null) 935 sealed = attr.getValue(Attributes.Name.SEALED); 936 return "true".equalsIgnoreCase(sealed); 937 } 938 939 // -- permissions 940 941 /** 942 * Returns the permissions for the given CodeSource. 943 */ 944 @Override getPermissions(CodeSource cs)945 protected PermissionCollection getPermissions(CodeSource cs) { 946 return new LazyCodeSourcePermissionCollection(super.getPermissions(cs), cs); 947 } 948 949 // -- miscellaneous supporting methods 950 951 /** 952 * Returns the ModuleReader for the given module, creating it if needed. 953 */ moduleReaderFor(ModuleReference mref)954 private ModuleReader moduleReaderFor(ModuleReference mref) { 955 ModuleReader reader = moduleToReader.get(mref); 956 if (reader == null) { 957 // avoid method reference during startup 958 Function<ModuleReference, ModuleReader> create = new Function<>() { 959 public ModuleReader apply(ModuleReference moduleReference) { 960 try { 961 return mref.open(); 962 } catch (IOException e) { 963 // Return a null module reader to avoid a future class 964 // load attempting to open the module again. 965 return new NullModuleReader(); 966 } 967 } 968 }; 969 reader = moduleToReader.computeIfAbsent(mref, create); 970 } 971 return reader; 972 } 973 974 /** 975 * A ModuleReader that doesn't read any resources. 976 */ 977 private static class NullModuleReader implements ModuleReader { 978 @Override find(String name)979 public Optional<URI> find(String name) { 980 return Optional.empty(); 981 } 982 @Override list()983 public Stream<String> list() { 984 return Stream.empty(); 985 } 986 @Override close()987 public void close() { 988 throw new InternalError("Should not get here"); 989 } 990 }; 991 992 /** 993 * Returns true if the given module opens the given package 994 * unconditionally. 995 * 996 * @implNote This method currently iterates over each of the open 997 * packages. This will be replaced once the ModuleDescriptor.Opens 998 * API is updated. 999 */ isOpen(ModuleReference mref, String pn)1000 private boolean isOpen(ModuleReference mref, String pn) { 1001 ModuleDescriptor descriptor = mref.descriptor(); 1002 if (descriptor.isOpen() || descriptor.isAutomatic()) 1003 return true; 1004 for (ModuleDescriptor.Opens opens : descriptor.opens()) { 1005 String source = opens.source(); 1006 if (!opens.isQualified() && source.equals(pn)) { 1007 return true; 1008 } 1009 } 1010 return false; 1011 } 1012 1013 /** 1014 * Checks access to the given URL. We use URLClassPath for consistent 1015 * checking with java.net.URLClassLoader. 1016 */ checkURL(URL url)1017 private static URL checkURL(URL url) { 1018 return URLClassPath.checkURL(url); 1019 } 1020 } 1021