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