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