changeset 7006:8210e5f2e21b

8044269: Analysis of archive files. Summary: Add checksum verification. Reviewed-by: iklam, dholmes, mschoene
author jiangli
date Tue, 12 Aug 2014 17:46:16 -0400
parents 609faa407cfd
children 42c091d63c72 cafabb1a240d
files src/share/vm/classfile/classLoader.cpp src/share/vm/classfile/classLoader.hpp src/share/vm/memory/filemap.cpp src/share/vm/memory/filemap.hpp src/share/vm/memory/metaspaceShared.cpp src/share/vm/runtime/arguments.cpp src/share/vm/runtime/globals.hpp
diffstat 7 files changed, 69 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/classfile/classLoader.cpp	Fri Aug 08 15:15:52 2014 -0700
+++ b/src/share/vm/classfile/classLoader.cpp	Tue Aug 12 17:46:16 2014 -0400
@@ -84,6 +84,7 @@
 typedef jboolean (JNICALL *ReadEntry_t)(jzfile *zip, jzentry *entry, unsigned char *buf, char *namebuf);
 typedef jboolean (JNICALL *ReadMappedEntry_t)(jzfile *zip, jzentry *entry, unsigned char **buf, char *namebuf);
 typedef jzentry* (JNICALL *GetNextEntry_t)(jzfile *zip, jint n);
+typedef jint     (JNICALL *Crc32_t)(jint crc, const jbyte *buf, jint len);
 
 static ZipOpen_t         ZipOpen            = NULL;
 static ZipClose_t        ZipClose           = NULL;
@@ -92,6 +93,7 @@
 static ReadMappedEntry_t ReadMappedEntry    = NULL;
 static GetNextEntry_t    GetNextEntry       = NULL;
 static canonicalize_fn_t CanonicalizeEntry  = NULL;
+static Crc32_t           Crc32              = NULL;
 
 // Globals
 
@@ -632,9 +634,11 @@
   ReadEntry    = CAST_TO_FN_PTR(ReadEntry_t, os::dll_lookup(handle, "ZIP_ReadEntry"));
   ReadMappedEntry = CAST_TO_FN_PTR(ReadMappedEntry_t, os::dll_lookup(handle, "ZIP_ReadMappedEntry"));
   GetNextEntry = CAST_TO_FN_PTR(GetNextEntry_t, os::dll_lookup(handle, "ZIP_GetNextEntry"));
+  Crc32        = CAST_TO_FN_PTR(Crc32_t, os::dll_lookup(handle, "ZIP_CRC32"));
 
   // ZIP_Close is not exported on Windows in JDK5.0 so don't abort if ZIP_Close is NULL
-  if (ZipOpen == NULL || FindEntry == NULL || ReadEntry == NULL || GetNextEntry == NULL) {
+  if (ZipOpen == NULL || FindEntry == NULL || ReadEntry == NULL ||
+      GetNextEntry == NULL || Crc32 == NULL) {
     vm_exit_during_initialization("Corrupted ZIP library", path);
   }
 
@@ -644,6 +648,11 @@
   // This lookup only works on 1.3. Do not check for non-null here
 }
 
+int ClassLoader::crc32(int crc, const char* buf, int len) {
+  assert(Crc32 != NULL, "ZIP_CRC32 is not found");
+  return (*Crc32)(crc, (const jbyte*)buf, len);
+}
+
 // PackageInfo data exists in order to support the java.lang.Package
 // class.  A Package object provides information about a java package
 // (version, vendor, etc.) which originates in the manifest of the jar
--- a/src/share/vm/classfile/classLoader.hpp	Fri Aug 08 15:15:52 2014 -0700
+++ b/src/share/vm/classfile/classLoader.hpp	Tue Aug 12 17:46:16 2014 -0400
@@ -215,6 +215,7 @@
   // to avoid confusing the zip library
   static bool get_canonical_path(char* orig, char* out, int len);
  public:
+  static int crc32(int crc, const char* buf, int len);
   // Used by the kernel jvm.
   static void update_class_path_entry_list(char *path,
                                            bool check_for_duplicates);
--- a/src/share/vm/memory/filemap.cpp	Fri Aug 08 15:15:52 2014 -0700
+++ b/src/share/vm/memory/filemap.cpp	Tue Aug 12 17:46:16 2014 -0400
@@ -177,7 +177,14 @@
     fail_continue("The shared archive file has the wrong version.");
     return false;
   }
-  _file_offset = (long)n;
+  size_t len = lseek(fd, 0, SEEK_END);
+  struct FileMapInfo::FileMapHeader::space_info* si =
+    &_header._space[MetaspaceShared::mc];
+  if (si->_file_offset >= len || len - si->_file_offset < si->_used) {
+    fail_continue("The shared archive file has been truncated.");
+    return false;
+  }
+  _file_offset = n;
   return true;
 }
 
@@ -268,6 +275,7 @@
   si->_capacity = capacity;
   si->_read_only = read_only;
   si->_allow_exec = allow_exec;
+  si->_crc = ClassLoader::crc32(0, base, (jint)size);
   write_bytes_aligned(base, (int)size);
 }
 
@@ -292,14 +300,15 @@
 // Align file position to an allocation unit boundary.
 
 void FileMapInfo::align_file_position() {
-  long new_file_offset = align_size_up(_file_offset, os::vm_allocation_granularity());
+  size_t new_file_offset = align_size_up(_file_offset,
+                                         os::vm_allocation_granularity());
   if (new_file_offset != _file_offset) {
     _file_offset = new_file_offset;
     if (_file_open) {
       // Seek one byte back from the target and write a byte to insure
       // that the written file is the correct length.
       _file_offset -= 1;
-      if (lseek(_fd, _file_offset, SEEK_SET) < 0) {
+      if (lseek(_fd, (long)_file_offset, SEEK_SET) < 0) {
         fail_stop("Unable to seek.", NULL);
       }
       char zero = 0;
@@ -406,6 +415,19 @@
   return base;
 }
 
+bool FileMapInfo::verify_region_checksum(int i) {
+  if (!VerifySharedSpaces) {
+    return true;
+  }
+  const char* buf = _header._space[i]._base;
+  size_t sz = _header._space[i]._used;
+  int crc = ClassLoader::crc32(0, buf, (jint)sz);
+  if (crc != _header._space[i]._crc) {
+    fail_continue("Checksum verification failed.");
+    return false;
+  }
+  return true;
+}
 
 // Unmap a memory region in the address space.
 
@@ -457,8 +479,20 @@
   return true;
 }
 
+int FileMapInfo::compute_header_crc() {
+  char* header = (char*)&_header;
+  // start computing from the field after _crc
+  char* buf = (char*)&_header._crc + sizeof(int);
+  size_t sz = sizeof(FileMapInfo::FileMapHeader) - (buf - header);
+  int crc = ClassLoader::crc32(0, buf, (jint)sz);
+  return crc;
+}
 
 bool FileMapInfo::validate() {
+  if (VerifySharedSpaces && compute_header_crc() != _header._crc) {
+    fail_continue("Header checksum verification failed.");
+    return false;
+  }
   if (_header._version != current_version()) {
     fail_continue("The shared archive file is the wrong version.");
     return false;
--- a/src/share/vm/memory/filemap.hpp	Fri Aug 08 15:15:52 2014 -0700
+++ b/src/share/vm/memory/filemap.hpp	Tue Aug 12 17:46:16 2014 -0400
@@ -54,7 +54,7 @@
 
   bool  _file_open;
   int   _fd;
-  long  _file_offset;
+  size_t  _file_offset;
 
   // FileMapHeader describes the shared space data in the file to be
   // mapped.  This structure gets written to a file.  It is not a class, so
@@ -62,12 +62,14 @@
 
   struct FileMapHeader {
     int    _magic;                    // identify file type.
+    int    _crc;                      // header crc checksum.
     int    _version;                  // (from enum, above.)
     size_t _alignment;                // how shared archive should be aligned
     int    _obj_alignment;            // value of ObjectAlignmentInBytes
 
     struct space_info {
-      int    _file_offset;   // sizeof(this) rounded to vm page size
+      int    _crc;           // crc checksum of the current space
+      size_t _file_offset;   // sizeof(this) rounded to vm page size
       char*  _base;          // copy-on-write base address
       size_t _capacity;      // for validity checking
       size_t _used;          // for setting space top on read
@@ -104,6 +106,8 @@
   }
 
   static int current_version()        { return _current_version; }
+  int    compute_header_crc();
+  void   set_header_crc(int crc)      { _header._crc = crc; }
   void   populate_header(size_t alignment);
   bool   validate();
   void   invalidate();
@@ -136,6 +140,7 @@
   void  write_bytes_aligned(const void* buffer, int count);
   char* map_region(int i);
   void  unmap_region(int i);
+  bool  verify_region_checksum(int i);
   void  close();
   bool  is_open() { return _file_open; }
   ReservedSpace reserve_shared_memory();
--- a/src/share/vm/memory/metaspaceShared.cpp	Fri Aug 08 15:15:52 2014 -0700
+++ b/src/share/vm/memory/metaspaceShared.cpp	Tue Aug 12 17:46:16 2014 -0400
@@ -585,6 +585,7 @@
 
   // Pass 2 - write data.
   mapinfo->open_for_write();
+  mapinfo->set_header_crc(mapinfo->compute_header_crc());
   mapinfo->write_header();
   mapinfo->write_space(MetaspaceShared::ro, _loader_data->ro_metaspace(), true);
   mapinfo->write_space(MetaspaceShared::rw, _loader_data->rw_metaspace(), false);
@@ -863,9 +864,13 @@
 
   // Map each shared region
   if ((_ro_base = mapinfo->map_region(ro)) != NULL &&
+       mapinfo->verify_region_checksum(ro) &&
       (_rw_base = mapinfo->map_region(rw)) != NULL &&
+       mapinfo->verify_region_checksum(rw) &&
       (_md_base = mapinfo->map_region(md)) != NULL &&
+       mapinfo->verify_region_checksum(md) &&
       (_mc_base = mapinfo->map_region(mc)) != NULL &&
+       mapinfo->verify_region_checksum(mc) &&
       (image_alignment == (size_t)max_alignment())) {
     // Success (no need to do anything)
     return true;
--- a/src/share/vm/runtime/arguments.cpp	Fri Aug 08 15:15:52 2014 -0700
+++ b/src/share/vm/runtime/arguments.cpp	Tue Aug 12 17:46:16 2014 -0400
@@ -3581,6 +3581,11 @@
     return JNI_ENOMEM;
   }
 
+  // Set up VerifySharedSpaces
+  if (FLAG_IS_DEFAULT(VerifySharedSpaces) && SharedArchiveFile != NULL) {
+    VerifySharedSpaces = true;
+  }
+
   // Delay warning until here so that we've had a chance to process
   // the -XX:-PrintWarnings flag
   if (needs_hotspotrc_warning) {
--- a/src/share/vm/runtime/globals.hpp	Fri Aug 08 15:15:52 2014 -0700
+++ b/src/share/vm/runtime/globals.hpp	Tue Aug 12 17:46:16 2014 -0400
@@ -3745,6 +3745,10 @@
   product(bool, UseSharedSpaces, true,                                      \
           "Use shared spaces for metadata")                                 \
                                                                             \
+  product(bool, VerifySharedSpaces, false,                                  \
+          "Verify shared spaces (false for default archive, true for "      \
+          "archive specified by -XX:SharedArchiveFile)")                    \
+                                                                            \
   product(bool, RequireSharedSpaces, false,                                 \
           "Require shared spaces for metadata")                             \
                                                                             \