1 /* 2 * Copyright (c) 2014, 2018, 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 "classfile/classLoader.hpp" 27 #include "classfile/classLoaderExt.hpp" 28 #include "classfile/dictionary.hpp" 29 #include "classfile/javaClasses.hpp" 30 #include "classfile/sharedClassUtil.hpp" 31 #include "classfile/stringTable.hpp" 32 #include "classfile/symbolTable.hpp" 33 #include "classfile/systemDictionary.hpp" 34 #include "classfile/systemDictionaryShared.hpp" 35 #include "memory/filemap.hpp" 36 #include "memory/metadataFactory.hpp" 37 #include "memory/resourceArea.hpp" 38 #include "oops/instanceKlass.hpp" 39 #include "runtime/arguments.hpp" 40 #include "runtime/java.hpp" 41 #include "runtime/os.inline.hpp" 42 43 class ManifestStream: public ResourceObj { 44 private: 45 u1* _buffer_start; // Buffer bottom 46 u1* _buffer_end; // Buffer top (one past last element) 47 u1* _current; // Current buffer position 48 49 public: 50 // Constructor 51 ManifestStream(u1* buffer, int length) : _buffer_start(buffer), 52 _current(buffer) { 53 _buffer_end = buffer + length; 54 } 55 56 static bool is_attr(u1* attr, const char* name) { 57 return strncmp((const char*)attr, name, strlen(name)) == 0; 58 } 59 60 static char* copy_attr(u1* value, size_t len) { 61 char* buf = NEW_RESOURCE_ARRAY(char, len + 1); 62 strncpy(buf, (char*)value, len); 63 buf[len] = 0; 64 return buf; 65 } 66 67 // The return value indicates if the JAR is signed or not 68 bool check_is_signed() { 69 u1* attr = _current; 70 bool isSigned = false; 71 while (_current < _buffer_end) { 72 if (*_current == '\n') { 73 *_current = '\0'; 74 u1* value = (u1*)strchr((char*)attr, ':'); 75 if (value != NULL) { 76 assert(*(value+1) == ' ', "Unrecognized format" ); 77 if (strstr((char*)attr, "-Digest") != NULL) { 78 isSigned = true; 79 break; 80 } 81 } 82 *_current = '\n'; // restore 83 attr = _current + 1; 84 } 85 _current ++; 86 } 87 return isSigned; 88 } 89 }; 90 91 void SharedPathsMiscInfoExt::print_path(outputStream* out, int type, const char* path) { 92 switch(type) { 93 case APP: 94 ClassLoader::trace_class_path("Expecting -Djava.class.path=", path); 95 break; 96 case MODULE: 97 ClassLoader::trace_class_path("Checking module path: ", path); 98 break; 99 default: 100 SharedPathsMiscInfo::print_path(out, type, path); 101 } 102 } 103 104 bool SharedPathsMiscInfoExt::check(jint type, const char* path) { 105 106 switch (type) { 107 case APP: 108 { 109 // Prefix is OK: E.g., dump with -cp foo.jar, but run with -cp foo.jar:bar.jar 110 size_t len = strlen(path); 111 const char *appcp = Arguments::get_appclasspath(); 112 assert(appcp != NULL, "NULL app classpath"); 113 size_t appcp_len = strlen(appcp); 114 if (appcp_len < len) { 115 return fail("Run time APP classpath is shorter than the one at dump time: ", appcp); 116 } 117 ResourceMark rm; 118 char* tmp_path; 119 if (len == appcp_len) { 120 tmp_path = (char*)appcp; 121 } else { 122 tmp_path = NEW_RESOURCE_ARRAY(char, len + 1); 123 strncpy(tmp_path, appcp, len); 124 tmp_path[len] = 0; 125 } 126 if (os::file_name_strcmp(path, tmp_path) != 0) { 127 return fail("[APP classpath mismatch, actual: -Djava.class.path=", appcp); 128 } 129 if (appcp[len] != '\0' && appcp[len] != os::path_separator()[0]) { 130 return fail("Dump time APP classpath is not a proper prefix of run time APP classpath: ", appcp); 131 } 132 } 133 break; 134 default: 135 return SharedPathsMiscInfo::check(type, path); 136 } 137 138 return true; 139 } 140 141 void SharedClassUtil::update_shared_classpath(ClassPathEntry *cpe, SharedClassPathEntry* e, TRAPS) { 142 ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data(); 143 SharedClassPathEntryExt* ent = (SharedClassPathEntryExt*)e; 144 ResourceMark rm(THREAD); 145 jint manifest_size; 146 bool isSigned; 147 148 if (cpe->is_jar_file()) { 149 char* manifest = ClassLoaderExt::read_manifest(cpe, &manifest_size, CHECK); 150 if (manifest != NULL) { 151 ManifestStream* stream = new ManifestStream((u1*)manifest, 152 manifest_size); 153 isSigned = stream->check_is_signed(); 154 if (isSigned) { 155 ent->_is_signed = true; 156 } else { 157 // Copy the manifest into the shared archive 158 manifest = ClassLoaderExt::read_raw_manifest(cpe, &manifest_size, CHECK); 159 Array<u1>* buf = MetadataFactory::new_array<u1>(loader_data, 160 manifest_size, 161 THREAD); 162 char* p = (char*)(buf->data()); 163 memcpy(p, manifest, manifest_size); 164 ent->set_manifest(buf); 165 ent->_is_signed = false; 166 } 167 } 168 } 169 } 170 171 void SharedClassUtil::initialize(TRAPS) { 172 if (UseSharedSpaces) { 173 int size = FileMapInfo::get_number_of_shared_paths(); 174 if (size > 0) { 175 SystemDictionaryShared::allocate_shared_data_arrays(size, THREAD); 176 FileMapHeaderExt* header = (FileMapHeaderExt*)FileMapInfo::current_info()->header(); 177 ClassLoaderExt::init_paths_start_index(header->_app_class_paths_start_index); 178 ClassLoaderExt::init_app_module_paths_start_index(header->_app_module_paths_start_index); 179 } 180 } 181 182 if (DumpSharedSpaces) { 183 if (SharedArchiveConfigFile) { 184 read_extra_data(SharedArchiveConfigFile, THREAD); 185 } 186 } 187 } 188 189 void SharedClassUtil::read_extra_data(const char* filename, TRAPS) { 190 HashtableTextDump reader(filename); 191 reader.check_version("VERSION: 1.0"); 192 193 while (reader.remain() > 0) { 194 int utf8_length; 195 int prefix_type = reader.scan_prefix(&utf8_length); 196 ResourceMark rm(THREAD); 197 char* utf8_buffer = NEW_RESOURCE_ARRAY(char, utf8_length); 198 reader.get_utf8(utf8_buffer, utf8_length); 199 200 if (prefix_type == HashtableTextDump::SymbolPrefix) { 201 SymbolTable::new_symbol(utf8_buffer, utf8_length, THREAD); 202 } else{ 203 assert(prefix_type == HashtableTextDump::StringPrefix, "Sanity"); 204 utf8_buffer[utf8_length] = '\0'; 205 oop s = StringTable::intern(utf8_buffer, THREAD); 206 } 207 } 208 } 209 210 bool SharedClassUtil::is_classpath_entry_signed(int classpath_index) { 211 assert(classpath_index >= 0, "Sanity"); 212 SharedClassPathEntryExt* ent = (SharedClassPathEntryExt*) 213 FileMapInfo::shared_path(classpath_index); 214 return ent->_is_signed; 215 } 216 217 void FileMapHeaderExt::populate(FileMapInfo* mapinfo, size_t alignment) { 218 FileMapInfo::FileMapHeader::populate(mapinfo, alignment); 219 220 ClassLoaderExt::finalize_shared_paths_misc_info(); 221 _app_class_paths_start_index = ClassLoaderExt::app_class_paths_start_index(); 222 _app_module_paths_start_index = ClassLoaderExt::app_module_paths_start_index(); 223 224 _verify_local = BytecodeVerificationLocal; 225 _verify_remote = BytecodeVerificationRemote; 226 _has_platform_or_app_classes = ClassLoaderExt::has_platform_or_app_classes(); 227 } 228 229 bool FileMapHeaderExt::validate() { 230 if (!FileMapInfo::FileMapHeader::validate()) { 231 return false; 232 } 233 234 // This must be done after header validation because it might change the 235 // header data 236 const char* prop = Arguments::get_property("java.system.class.loader"); 237 if (prop != NULL) { 238 warning("Archived non-system classes are disabled because the " 239 "java.system.class.loader property is specified (value = \"%s\"). " 240 "To use archived non-system classes, this property must be not be set", prop); 241 _has_platform_or_app_classes = false; 242 } 243 244 // For backwards compatibility, we don't check the verification setting 245 // if the archive only contains system classes. 246 if (_has_platform_or_app_classes && 247 ((!_verify_local && BytecodeVerificationLocal) || 248 (!_verify_remote && BytecodeVerificationRemote))) { 249 FileMapInfo::fail_continue("The shared archive file was created with less restrictive " 250 "verification setting than the current setting."); 251 return false; 252 } 253 254 return true; 255 }