1 /* 2 * Copyright (c) 2021, 2024, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include "precompiled.hpp" 26 #include "cds/cdsConfig.hpp" 27 #include "cds/cdsProtectionDomain.hpp" 28 #include "classfile/classLoader.hpp" 29 #include "classfile/classLoaderData.inline.hpp" 30 #include "classfile/classLoaderExt.hpp" 31 #include "classfile/javaClasses.hpp" 32 #include "classfile/moduleEntry.hpp" 33 #include "classfile/systemDictionaryShared.hpp" 34 #include "classfile/vmClasses.hpp" 35 #include "classfile/vmSymbols.hpp" 36 #include "memory/oopFactory.hpp" 37 #include "memory/resourceArea.hpp" 38 #include "memory/universe.hpp" 39 #include "oops/instanceKlass.hpp" 40 #include "oops/symbol.hpp" 41 #include "runtime/javaCalls.hpp" 42 43 OopHandle CDSProtectionDomain::_shared_protection_domains; 44 OopHandle CDSProtectionDomain::_shared_jar_urls; 45 OopHandle CDSProtectionDomain::_shared_jar_manifests; 46 47 // Initializes the java.lang.Package and java.security.ProtectionDomain objects associated with 48 // the given InstanceKlass. 49 // Returns the ProtectionDomain for the InstanceKlass. 50 Handle CDSProtectionDomain::init_security_info(Handle class_loader, InstanceKlass* ik, PackageEntry* pkg_entry, TRAPS) { 51 int index = ik->shared_classpath_index(); 52 assert(index >= 0, "Sanity"); 53 SharedClassPathEntry* ent = FileMapInfo::shared_path(index); 54 Symbol* class_name = ik->name(); 55 56 if (ent->is_modules_image()) { 57 // For shared app/platform classes originated from the run-time image: 58 // The ProtectionDomains are cached in the corresponding ModuleEntries 59 // for fast access by the VM. 60 // all packages from module image are already created during VM bootstrap in 61 // Modules::define_module(). 62 assert(pkg_entry != nullptr, "archived class in module image cannot be from unnamed package"); 63 ModuleEntry* mod_entry = pkg_entry->module(); 64 return get_shared_protection_domain(class_loader, mod_entry, THREAD); 65 } else { 66 // For shared app/platform classes originated from JAR files on the class path: 67 // Each of the 3 SystemDictionaryShared::_shared_xxx arrays has the same length 68 // as the shared classpath table in the shared archive (see 69 // FileMap::_shared_path_table in filemap.hpp for details). 70 // 71 // If a shared InstanceKlass k is loaded from the class path, let 72 // 73 // index = k->shared_classpath_index(): 74 // 75 // FileMap::_shared_path_table[index] identifies the JAR file that contains k. 76 // 77 // k's protection domain is: 78 // 79 // ProtectionDomain pd = _shared_protection_domains[index]; 80 // 81 // and k's Package is initialized using 82 // 83 // manifest = _shared_jar_manifests[index]; 84 // url = _shared_jar_urls[index]; 85 // define_shared_package(class_name, class_loader, manifest, url, CHECK_NH); 86 // 87 // Note that if an element of these 3 _shared_xxx arrays is null, it will be initialized by 88 // the corresponding SystemDictionaryShared::get_shared_xxx() function. 89 Handle manifest = get_shared_jar_manifest(index, CHECK_NH); 90 Handle url = get_shared_jar_url(index, CHECK_NH); 91 if (!CDSConfig::is_loading_packages()) { 92 int index_offset = index - ClassLoaderExt::app_class_paths_start_index(); 93 if (index_offset < PackageEntry::max_index_for_defined_in_class_path()) { 94 if (pkg_entry == nullptr || !pkg_entry->is_defined_by_cds_in_class_path(index_offset)) { 95 // define_shared_package only needs to be called once for each package in a jar specified 96 // in the shared class path. 97 define_shared_package(class_name, class_loader, manifest, url, CHECK_NH); 98 if (pkg_entry != nullptr) { 99 pkg_entry->set_defined_by_cds_in_class_path(index_offset); 100 } 101 } 102 } else { 103 define_shared_package(class_name, class_loader, manifest, url, CHECK_NH); 104 } 105 } 106 return get_shared_protection_domain(class_loader, index, url, THREAD); 107 } 108 } 109 110 Handle CDSProtectionDomain::get_package_name(Symbol* class_name, TRAPS) { 111 ResourceMark rm(THREAD); 112 Handle pkgname_string; 113 TempNewSymbol pkg = ClassLoader::package_from_class_name(class_name); 114 if (pkg != nullptr) { // Package prefix found 115 const char* pkgname = pkg->as_klass_external_name(); 116 pkgname_string = java_lang_String::create_from_str(pkgname, 117 CHECK_(pkgname_string)); 118 } 119 return pkgname_string; 120 } 121 122 PackageEntry* CDSProtectionDomain::get_package_entry_from_class(InstanceKlass* ik, Handle class_loader) { 123 PackageEntry* pkg_entry = ik->package(); 124 if (CDSConfig::is_using_full_module_graph() && ik->is_shared() && pkg_entry != nullptr) { 125 assert(MetaspaceShared::is_in_shared_metaspace(pkg_entry), "must be"); 126 assert(!ik->is_shared_unregistered_class(), "unexpected archived package entry for an unregistered class"); 127 assert(ik->module()->is_named(), "unexpected archived package entry for a class in an unnamed module"); 128 return pkg_entry; 129 } 130 TempNewSymbol pkg_name = ClassLoader::package_from_class_name(ik->name()); 131 if (pkg_name != nullptr) { 132 pkg_entry = ClassLoaderData::class_loader_data(class_loader())->packages()->lookup_only(pkg_name); 133 } else { 134 pkg_entry = nullptr; 135 } 136 return pkg_entry; 137 } 138 139 // Define Package for shared app classes from JAR file and also checks for 140 // package sealing (all done in Java code) 141 // See http://docs.oracle.com/javase/tutorial/deployment/jar/sealman.html 142 void CDSProtectionDomain::define_shared_package(Symbol* class_name, 143 Handle class_loader, 144 Handle manifest, 145 Handle url, 146 TRAPS) { 147 assert(SystemDictionary::is_system_class_loader(class_loader()), "unexpected class loader"); 148 // get_package_name() returns a null handle if the class is in unnamed package 149 Handle pkgname_string = get_package_name(class_name, CHECK); 150 if (pkgname_string.not_null()) { 151 Klass* app_classLoader_klass = vmClasses::jdk_internal_loader_ClassLoaders_AppClassLoader_klass(); 152 JavaValue result(T_OBJECT); 153 JavaCallArguments args(3); 154 args.set_receiver(class_loader); 155 args.push_oop(pkgname_string); 156 args.push_oop(manifest); 157 args.push_oop(url); 158 JavaCalls::call_virtual(&result, app_classLoader_klass, 159 vmSymbols::defineOrCheckPackage_name(), 160 vmSymbols::defineOrCheckPackage_signature(), 161 &args, 162 CHECK); 163 } 164 } 165 166 Handle CDSProtectionDomain::create_jar_manifest(const char* manifest_chars, size_t size, TRAPS) { 167 typeArrayOop buf = oopFactory::new_byteArray((int)size, CHECK_NH); 168 typeArrayHandle bufhandle(THREAD, buf); 169 ArrayAccess<>::arraycopy_from_native(reinterpret_cast<const jbyte*>(manifest_chars), 170 buf, typeArrayOopDesc::element_offset<jbyte>(0), size); 171 Handle bais = JavaCalls::construct_new_instance(vmClasses::ByteArrayInputStream_klass(), 172 vmSymbols::byte_array_void_signature(), 173 bufhandle, CHECK_NH); 174 // manifest = new Manifest(ByteArrayInputStream) 175 Handle manifest = JavaCalls::construct_new_instance(vmClasses::Jar_Manifest_klass(), 176 vmSymbols::input_stream_void_signature(), 177 bais, CHECK_NH); 178 return manifest; 179 } 180 181 Handle CDSProtectionDomain::get_shared_jar_manifest(int shared_path_index, TRAPS) { 182 Handle manifest; 183 if (shared_jar_manifest(shared_path_index) == nullptr) { 184 SharedClassPathEntry* ent = FileMapInfo::shared_path(shared_path_index); 185 size_t size = (size_t)ent->manifest_size(); 186 if (size == 0) { 187 return Handle(); 188 } 189 190 // ByteArrayInputStream bais = new ByteArrayInputStream(buf); 191 const char* src = ent->manifest(); 192 assert(src != nullptr, "No Manifest data"); 193 manifest = create_jar_manifest(src, size, CHECK_NH); 194 atomic_set_shared_jar_manifest(shared_path_index, manifest()); 195 } 196 manifest = Handle(THREAD, shared_jar_manifest(shared_path_index)); 197 assert(manifest.not_null(), "sanity"); 198 return manifest; 199 } 200 201 Handle CDSProtectionDomain::get_shared_jar_url(int shared_path_index, TRAPS) { 202 Handle url_h; 203 if (shared_jar_url(shared_path_index) == nullptr) { 204 JavaValue result(T_OBJECT); 205 const char* path = FileMapInfo::shared_path_name(shared_path_index); 206 Handle path_string = java_lang_String::create_from_str(path, CHECK_(url_h)); 207 Klass* classLoaders_klass = 208 vmClasses::jdk_internal_loader_ClassLoaders_klass(); 209 JavaCalls::call_static(&result, classLoaders_klass, 210 vmSymbols::toFileURL_name(), 211 vmSymbols::toFileURL_signature(), 212 path_string, CHECK_(url_h)); 213 214 atomic_set_shared_jar_url(shared_path_index, result.get_oop()); 215 } 216 217 url_h = Handle(THREAD, shared_jar_url(shared_path_index)); 218 assert(url_h.not_null(), "sanity"); 219 return url_h; 220 } 221 222 // Get the ProtectionDomain associated with the CodeSource from the classloader. 223 Handle CDSProtectionDomain::get_protection_domain_from_classloader(Handle class_loader, 224 Handle url, TRAPS) { 225 // CodeSource cs = new CodeSource(url, null); 226 Handle cs = JavaCalls::construct_new_instance(vmClasses::CodeSource_klass(), 227 vmSymbols::url_code_signer_array_void_signature(), 228 url, Handle(), CHECK_NH); 229 230 // protection_domain = SecureClassLoader.getProtectionDomain(cs); 231 Klass* secureClassLoader_klass = vmClasses::SecureClassLoader_klass(); 232 JavaValue obj_result(T_OBJECT); 233 JavaCalls::call_virtual(&obj_result, class_loader, secureClassLoader_klass, 234 vmSymbols::getProtectionDomain_name(), 235 vmSymbols::getProtectionDomain_signature(), 236 cs, CHECK_NH); 237 return Handle(THREAD, obj_result.get_oop()); 238 } 239 240 // Returns the ProtectionDomain associated with the JAR file identified by the url. 241 Handle CDSProtectionDomain::get_shared_protection_domain(Handle class_loader, 242 int shared_path_index, 243 Handle url, 244 TRAPS) { 245 Handle protection_domain; 246 if (shared_protection_domain(shared_path_index) == nullptr) { 247 Handle pd = get_protection_domain_from_classloader(class_loader, url, CHECK_NH); 248 atomic_set_shared_protection_domain(shared_path_index, pd()); 249 } 250 251 // Acquire from the cache because if another thread beats the current one to 252 // set the shared protection_domain and the atomic_set fails, the current thread 253 // needs to get the updated protection_domain from the cache. 254 protection_domain = Handle(THREAD, shared_protection_domain(shared_path_index)); 255 assert(protection_domain.not_null(), "sanity"); 256 return protection_domain; 257 } 258 259 // Returns the ProtectionDomain associated with the moduleEntry. 260 Handle CDSProtectionDomain::get_shared_protection_domain(Handle class_loader, 261 ModuleEntry* mod, TRAPS) { 262 ClassLoaderData *loader_data = mod->loader_data(); 263 if (mod->shared_protection_domain() == nullptr) { 264 Symbol* location = mod->location(); 265 if (location != nullptr) { 266 Handle location_string = java_lang_String::create_from_symbol( 267 location, CHECK_NH); 268 Handle url; 269 JavaValue result(T_OBJECT); 270 if (location->starts_with("jrt:/")) { 271 url = JavaCalls::construct_new_instance(vmClasses::URL_klass(), 272 vmSymbols::string_void_signature(), 273 location_string, CHECK_NH); 274 } else { 275 Klass* classLoaders_klass = 276 vmClasses::jdk_internal_loader_ClassLoaders_klass(); 277 JavaCalls::call_static(&result, classLoaders_klass, vmSymbols::toFileURL_name(), 278 vmSymbols::toFileURL_signature(), 279 location_string, CHECK_NH); 280 url = Handle(THREAD, result.get_oop()); 281 } 282 283 Handle pd = get_protection_domain_from_classloader(class_loader, url, 284 CHECK_NH); 285 mod->set_shared_protection_domain(loader_data, pd); 286 } 287 } 288 289 Handle protection_domain(THREAD, mod->shared_protection_domain()); 290 assert(protection_domain.not_null(), "sanity"); 291 return protection_domain; 292 } 293 294 void CDSProtectionDomain::atomic_set_array_index(OopHandle array, int index, oop o) { 295 // Benign race condition: array.obj_at(index) may already be filled in. 296 // The important thing here is that all threads pick up the same result. 297 // It doesn't matter which racing thread wins, as long as only one 298 // result is used by all threads, and all future queries. 299 ((objArrayOop)array.resolve())->replace_if_null(index, o); 300 } 301 302 oop CDSProtectionDomain::shared_protection_domain(int index) { 303 return ((objArrayOop)_shared_protection_domains.resolve())->obj_at(index); 304 } 305 306 void CDSProtectionDomain::allocate_shared_protection_domain_array(int size, TRAPS) { 307 if (_shared_protection_domains.resolve() == nullptr) { 308 oop spd = oopFactory::new_objArray( 309 vmClasses::ProtectionDomain_klass(), size, CHECK); 310 _shared_protection_domains = OopHandle(Universe::vm_global(), spd); 311 } 312 } 313 314 oop CDSProtectionDomain::shared_jar_url(int index) { 315 return ((objArrayOop)_shared_jar_urls.resolve())->obj_at(index); 316 } 317 318 void CDSProtectionDomain::allocate_shared_jar_url_array(int size, TRAPS) { 319 if (_shared_jar_urls.resolve() == nullptr) { 320 oop sju = oopFactory::new_objArray( 321 vmClasses::URL_klass(), size, CHECK); 322 _shared_jar_urls = OopHandle(Universe::vm_global(), sju); 323 } 324 } 325 326 oop CDSProtectionDomain::shared_jar_manifest(int index) { 327 return ((objArrayOop)_shared_jar_manifests.resolve())->obj_at(index); 328 } 329 330 void CDSProtectionDomain::allocate_shared_jar_manifest_array(int size, TRAPS) { 331 if (_shared_jar_manifests.resolve() == nullptr) { 332 oop sjm = oopFactory::new_objArray( 333 vmClasses::Jar_Manifest_klass(), size, CHECK); 334 _shared_jar_manifests = OopHandle(Universe::vm_global(), sjm); 335 } 336 }