1 /* 2 * Copyright (c) 2021, 2025, 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 "cds/aotClassLocation.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/javaClasses.hpp" 31 #include "classfile/moduleEntry.hpp" 32 #include "classfile/systemDictionaryShared.hpp" 33 #include "classfile/vmClasses.hpp" 34 #include "classfile/vmSymbols.hpp" 35 #include "memory/oopFactory.hpp" 36 #include "memory/resourceArea.hpp" 37 #include "memory/universe.hpp" 38 #include "oops/instanceKlass.hpp" 39 #include "oops/symbol.hpp" 40 #include "runtime/javaCalls.hpp" 41 42 OopHandle CDSProtectionDomain::_shared_protection_domains; 43 OopHandle CDSProtectionDomain::_shared_jar_urls; 44 OopHandle CDSProtectionDomain::_shared_jar_manifests; 45 46 // Initializes the java.lang.Package and java.security.ProtectionDomain objects associated with 47 // the given InstanceKlass. 48 // Returns the ProtectionDomain for the InstanceKlass. 49 Handle CDSProtectionDomain::init_security_info(Handle class_loader, InstanceKlass* ik, PackageEntry* pkg_entry, TRAPS) { 50 int index = ik->shared_classpath_index(); 51 assert(index >= 0, "Sanity"); 52 const AOTClassLocation* cl = AOTClassLocationConfig::runtime()->class_location_at(index); 53 Symbol* class_name = ik->name(); 54 55 if (cl->is_modules_image()) { 56 // For shared app/platform classes originated from the run-time image: 57 // The ProtectionDomains are cached in the corresponding ModuleEntries 58 // for fast access by the VM. 59 // all packages from module image are already created during VM bootstrap in 60 // Modules::define_module(). 61 assert(pkg_entry != nullptr, "archived class in module image cannot be from unnamed package"); 62 Handle archived_pd = get_archived_protection_domain(THREAD, ik); 63 if (archived_pd.not_null()) { 64 return archived_pd; 65 } 66 ModuleEntry* mod_entry = pkg_entry->module(); 67 return get_shared_protection_domain(class_loader, mod_entry, THREAD); 68 } else { 69 // For shared app/platform classes originated from JAR files on the class path: 70 // Each of the 3 CDSProtectionDomain::_shared_xxx arrays has the same length 71 // as the shared classpath table in the shared archive. 72 // 73 // If a shared InstanceKlass k is loaded from the class path, let 74 // 75 // index = k->shared_classpath_index(); 76 // 77 // AOTClassLocationConfig::_runtime_instance->_array->at(index) identifies the JAR file that contains k. 78 // 79 // k's protection domain is: 80 // 81 // ProtectionDomain pd = _shared_protection_domains[index]; 82 // 83 // and k's Package is initialized using 84 // 85 // manifest = _shared_jar_manifests[index]; 86 // url = _shared_jar_urls[index]; 87 // define_shared_package(class_name, class_loader, manifest, url, CHECK_NH); 88 // 89 // Note that if an element of these 3 _shared_xxx arrays is null, it will be initialized by 90 // the corresponding CDSProtectionDomain::get_shared_xxx() function. 91 Handle manifest = get_shared_jar_manifest(index, CHECK_NH); 92 Handle url = get_shared_jar_url(index, CHECK_NH); 93 if (!CDSConfig::is_loading_packages()) { // leyden 94 int index_offset = index - AOTClassLocationConfig::runtime()->app_cp_start_index(); 95 if (index_offset < PackageEntry::max_index_for_defined_in_class_path()) { 96 if (pkg_entry == nullptr || !pkg_entry->is_defined_by_cds_in_class_path(index_offset)) { 97 // define_shared_package only needs to be called once for each package in a jar specified 98 // in the shared class path. 99 define_shared_package(class_name, class_loader, manifest, url, CHECK_NH); 100 if (pkg_entry != nullptr) { 101 pkg_entry->set_defined_by_cds_in_class_path(index_offset); 102 } 103 } else { 104 define_shared_package(class_name, class_loader, manifest, url, CHECK_NH); 105 } 106 } 107 } // leyden-end 108 Handle archived_pd = get_archived_protection_domain(THREAD, ik); 109 if (archived_pd.not_null()) { 110 return archived_pd; 111 } 112 return get_shared_protection_domain(class_loader, index, url, THREAD); 113 } 114 } 115 116 Handle CDSProtectionDomain::get_package_name(Symbol* class_name, TRAPS) { 117 ResourceMark rm(THREAD); 118 Handle pkgname_string; 119 TempNewSymbol pkg = ClassLoader::package_from_class_name(class_name); 120 if (pkg != nullptr) { // Package prefix found 121 const char* pkgname = pkg->as_klass_external_name(); 122 pkgname_string = java_lang_String::create_from_str(pkgname, 123 CHECK_(pkgname_string)); 124 } 125 return pkgname_string; 126 } 127 128 PackageEntry* CDSProtectionDomain::get_package_entry_from_class(InstanceKlass* ik, Handle class_loader) { 129 PackageEntry* pkg_entry = ik->package(); 130 if (CDSConfig::is_using_full_module_graph() && ik->in_aot_cache() && pkg_entry != nullptr) { 131 assert(AOTMetaspace::in_aot_cache(pkg_entry), "must be"); 132 assert(!ik->defined_by_other_loaders(), "unexpected archived package entry for an unregistered class"); 133 return pkg_entry; 134 } 135 TempNewSymbol pkg_name = ClassLoader::package_from_class_name(ik->name()); 136 if (pkg_name != nullptr) { 137 pkg_entry = ClassLoaderData::class_loader_data(class_loader())->packages()->lookup_only(pkg_name); 138 } else { 139 pkg_entry = nullptr; 140 } 141 return pkg_entry; 142 } 143 144 // Define Package for shared app classes from JAR file and also checks for 145 // package sealing (all done in Java code) 146 // See http://docs.oracle.com/javase/tutorial/deployment/jar/sealman.html 147 void CDSProtectionDomain::define_shared_package(Symbol* class_name, 148 Handle class_loader, 149 Handle manifest, 150 Handle url, 151 TRAPS) { 152 assert(SystemDictionary::is_system_class_loader(class_loader()), "unexpected class loader"); 153 // get_package_name() returns a null handle if the class is in unnamed package 154 Handle pkgname_string = get_package_name(class_name, CHECK); 155 if (pkgname_string.not_null()) { 156 Klass* app_classLoader_klass = vmClasses::jdk_internal_loader_ClassLoaders_AppClassLoader_klass(); 157 JavaValue result(T_OBJECT); 158 JavaCallArguments args(3); 159 args.set_receiver(class_loader); 160 args.push_oop(pkgname_string); 161 args.push_oop(manifest); 162 args.push_oop(url); 163 JavaCalls::call_virtual(&result, app_classLoader_klass, 164 vmSymbols::defineOrCheckPackage_name(), 165 vmSymbols::defineOrCheckPackage_signature(), 166 &args, 167 CHECK); 168 } 169 } 170 171 Handle CDSProtectionDomain::create_jar_manifest(const char* manifest_chars, size_t size, TRAPS) { 172 typeArrayOop buf = oopFactory::new_byteArray((int)size, CHECK_NH); 173 typeArrayHandle bufhandle(THREAD, buf); 174 ArrayAccess<>::arraycopy_from_native(reinterpret_cast<const jbyte*>(manifest_chars), 175 buf, typeArrayOopDesc::element_offset<jbyte>(0), size); 176 Handle bais = JavaCalls::construct_new_instance(vmClasses::ByteArrayInputStream_klass(), 177 vmSymbols::byte_array_void_signature(), 178 bufhandle, CHECK_NH); 179 // manifest = new Manifest(ByteArrayInputStream) 180 Handle manifest = JavaCalls::construct_new_instance(vmClasses::Jar_Manifest_klass(), 181 vmSymbols::input_stream_void_signature(), 182 bais, CHECK_NH); 183 return manifest; 184 } 185 186 Handle CDSProtectionDomain::get_shared_jar_manifest(int shared_path_index, TRAPS) { 187 Handle manifest; 188 if (shared_jar_manifest(shared_path_index) == nullptr) { 189 const AOTClassLocation* cl = AOTClassLocationConfig::runtime()->class_location_at(shared_path_index); 190 size_t size = cl->manifest_length(); 191 if (size == 0) { 192 return Handle(); 193 } 194 195 // ByteArrayInputStream bais = new ByteArrayInputStream(buf); 196 const char* src = cl->manifest(); 197 assert(src != nullptr, "No Manifest data"); 198 manifest = create_jar_manifest(src, size, CHECK_NH); 199 atomic_set_shared_jar_manifest(shared_path_index, manifest()); 200 } 201 manifest = Handle(THREAD, shared_jar_manifest(shared_path_index)); 202 assert(manifest.not_null(), "sanity"); 203 return manifest; 204 } 205 206 Handle CDSProtectionDomain::get_shared_jar_url(int shared_path_index, TRAPS) { 207 Handle url_h; 208 if (shared_jar_url(shared_path_index) == nullptr) { 209 const char* path = AOTClassLocationConfig::runtime()->class_location_at(shared_path_index)->path(); 210 oop result_oop = to_file_URL(path, url_h, CHECK_(url_h)); 211 atomic_set_shared_jar_url(shared_path_index, result_oop); 212 } 213 214 url_h = Handle(THREAD, shared_jar_url(shared_path_index)); 215 assert(url_h.not_null(), "sanity"); 216 return url_h; 217 } 218 219 220 Handle CDSProtectionDomain::get_archived_protection_domain(JavaThread* current, InstanceKlass* klass) { 221 oop pd = nullptr; 222 223 if (CDSConfig::is_loading_protection_domains()) { 224 oop mirror; 225 if (klass->has_archived_mirror_index()) { 226 mirror = klass->archived_java_mirror(); 227 } else { 228 mirror = klass->java_mirror(); 229 } 230 231 if (mirror != nullptr) { 232 pd = java_lang_Class::protection_domain(mirror); 233 } 234 } 235 236 if (log_is_enabled(Info, cds, protectiondomain)) { 237 ResourceMark rm; 238 log_info(cds, protectiondomain)("Archived protection domain for %s = %s", klass->external_name(), 239 (pd == nullptr) ? "none" : "found"); 240 } 241 242 if (pd == nullptr) { 243 return Handle(); 244 } else { 245 return Handle(current, pd); 246 } 247 } 248 249 oop CDSProtectionDomain::to_file_URL(const char* path, Handle url_h, TRAPS) { 250 JavaValue result(T_OBJECT); 251 Handle path_string = java_lang_String::create_from_str(path, CHECK_NULL); 252 JavaCalls::call_static(&result, 253 vmClasses::jdk_internal_loader_ClassLoaders_klass(), 254 vmSymbols::toFileURL_name(), 255 vmSymbols::toFileURL_signature(), 256 path_string, CHECK_NULL); 257 return result.get_oop(); 258 } 259 260 // Get the ProtectionDomain associated with the CodeSource from the classloader. 261 Handle CDSProtectionDomain::get_protection_domain_from_classloader(Handle class_loader, 262 Handle url, TRAPS) { 263 // CodeSource cs = new CodeSource(url, null); 264 Handle cs = JavaCalls::construct_new_instance(vmClasses::CodeSource_klass(), 265 vmSymbols::url_code_signer_array_void_signature(), 266 url, Handle(), CHECK_NH); 267 268 // protection_domain = SecureClassLoader.getProtectionDomain(cs); 269 Klass* secureClassLoader_klass = vmClasses::SecureClassLoader_klass(); 270 JavaValue obj_result(T_OBJECT); 271 JavaCalls::call_virtual(&obj_result, class_loader, secureClassLoader_klass, 272 vmSymbols::getProtectionDomain_name(), 273 vmSymbols::getProtectionDomain_signature(), 274 cs, CHECK_NH); 275 return Handle(THREAD, obj_result.get_oop()); 276 } 277 278 // Returns the ProtectionDomain associated with the JAR file identified by the url. 279 Handle CDSProtectionDomain::get_shared_protection_domain(Handle class_loader, 280 int shared_path_index, 281 Handle url, 282 TRAPS) { 283 Handle protection_domain; 284 if (shared_protection_domain(shared_path_index) == nullptr) { 285 Handle pd = get_protection_domain_from_classloader(class_loader, url, CHECK_NH); 286 atomic_set_shared_protection_domain(shared_path_index, pd()); 287 } 288 289 // Acquire from the cache because if another thread beats the current one to 290 // set the shared protection_domain and the atomic_set fails, the current thread 291 // needs to get the updated protection_domain from the cache. 292 protection_domain = Handle(THREAD, shared_protection_domain(shared_path_index)); 293 assert(protection_domain.not_null(), "sanity"); 294 return protection_domain; 295 } 296 297 // Returns the ProtectionDomain associated with the moduleEntry. 298 Handle CDSProtectionDomain::get_shared_protection_domain(Handle class_loader, 299 ModuleEntry* mod, TRAPS) { 300 ClassLoaderData *loader_data = mod->loader_data(); 301 if (mod->shared_protection_domain() == nullptr) { 302 Symbol* location = mod->location(); 303 if (location != nullptr) { 304 Handle location_string = java_lang_String::create_from_symbol( 305 location, CHECK_NH); 306 Handle url; 307 JavaValue result(T_OBJECT); 308 if (location->starts_with("jrt:/")) { 309 url = JavaCalls::construct_new_instance(vmClasses::URL_klass(), 310 vmSymbols::string_void_signature(), 311 location_string, CHECK_NH); 312 } else { 313 Klass* classLoaders_klass = 314 vmClasses::jdk_internal_loader_ClassLoaders_klass(); 315 JavaCalls::call_static(&result, classLoaders_klass, vmSymbols::toFileURL_name(), 316 vmSymbols::toFileURL_signature(), 317 location_string, CHECK_NH); 318 url = Handle(THREAD, result.get_oop()); 319 } 320 321 Handle pd = get_protection_domain_from_classloader(class_loader, url, 322 CHECK_NH); 323 mod->set_shared_protection_domain(loader_data, pd); 324 } 325 } 326 327 Handle protection_domain(THREAD, mod->shared_protection_domain()); 328 assert(protection_domain.not_null(), "sanity"); 329 return protection_domain; 330 } 331 332 void CDSProtectionDomain::atomic_set_array_index(OopHandle array, int index, oop o) { 333 // Benign race condition: array.obj_at(index) may already be filled in. 334 // The important thing here is that all threads pick up the same result. 335 // It doesn't matter which racing thread wins, as long as only one 336 // result is used by all threads, and all future queries. 337 ((objArrayOop)array.resolve())->replace_if_null(index, o); 338 } 339 340 oop CDSProtectionDomain::shared_protection_domain(int index) { 341 return ((objArrayOop)_shared_protection_domains.resolve())->obj_at(index); 342 } 343 344 void CDSProtectionDomain::allocate_shared_protection_domain_array(int size, TRAPS) { 345 if (_shared_protection_domains.resolve() == nullptr) { 346 oop spd = oopFactory::new_objArray( 347 vmClasses::ProtectionDomain_klass(), size, CHECK); 348 _shared_protection_domains = OopHandle(Universe::vm_global(), spd); 349 } 350 } 351 352 oop CDSProtectionDomain::shared_jar_url(int index) { 353 return ((objArrayOop)_shared_jar_urls.resolve())->obj_at(index); 354 } 355 356 void CDSProtectionDomain::allocate_shared_jar_url_array(int size, TRAPS) { 357 if (_shared_jar_urls.resolve() == nullptr) { 358 oop sju = oopFactory::new_objArray( 359 vmClasses::URL_klass(), size, CHECK); 360 _shared_jar_urls = OopHandle(Universe::vm_global(), sju); 361 } 362 } 363 364 oop CDSProtectionDomain::shared_jar_manifest(int index) { 365 return ((objArrayOop)_shared_jar_manifests.resolve())->obj_at(index); 366 } 367 368 void CDSProtectionDomain::allocate_shared_jar_manifest_array(int size, TRAPS) { 369 if (_shared_jar_manifests.resolve() == nullptr) { 370 oop sjm = oopFactory::new_objArray( 371 vmClasses::Jar_Manifest_klass(), size, CHECK); 372 _shared_jar_manifests = OopHandle(Universe::vm_global(), sjm); 373 } 374 }