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 }