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