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