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