Tue, 12 Aug 2014 17:46:16 -0400
8044269: Analysis of archive files.
Summary: Add checksum verification.
Reviewed-by: iklam, dholmes, mschoene
1.1 --- a/src/share/vm/classfile/classLoader.cpp Fri Aug 08 15:15:52 2014 -0700 1.2 +++ b/src/share/vm/classfile/classLoader.cpp Tue Aug 12 17:46:16 2014 -0400 1.3 @@ -84,6 +84,7 @@ 1.4 typedef jboolean (JNICALL *ReadEntry_t)(jzfile *zip, jzentry *entry, unsigned char *buf, char *namebuf); 1.5 typedef jboolean (JNICALL *ReadMappedEntry_t)(jzfile *zip, jzentry *entry, unsigned char **buf, char *namebuf); 1.6 typedef jzentry* (JNICALL *GetNextEntry_t)(jzfile *zip, jint n); 1.7 +typedef jint (JNICALL *Crc32_t)(jint crc, const jbyte *buf, jint len); 1.8 1.9 static ZipOpen_t ZipOpen = NULL; 1.10 static ZipClose_t ZipClose = NULL; 1.11 @@ -92,6 +93,7 @@ 1.12 static ReadMappedEntry_t ReadMappedEntry = NULL; 1.13 static GetNextEntry_t GetNextEntry = NULL; 1.14 static canonicalize_fn_t CanonicalizeEntry = NULL; 1.15 +static Crc32_t Crc32 = NULL; 1.16 1.17 // Globals 1.18 1.19 @@ -632,9 +634,11 @@ 1.20 ReadEntry = CAST_TO_FN_PTR(ReadEntry_t, os::dll_lookup(handle, "ZIP_ReadEntry")); 1.21 ReadMappedEntry = CAST_TO_FN_PTR(ReadMappedEntry_t, os::dll_lookup(handle, "ZIP_ReadMappedEntry")); 1.22 GetNextEntry = CAST_TO_FN_PTR(GetNextEntry_t, os::dll_lookup(handle, "ZIP_GetNextEntry")); 1.23 + Crc32 = CAST_TO_FN_PTR(Crc32_t, os::dll_lookup(handle, "ZIP_CRC32")); 1.24 1.25 // ZIP_Close is not exported on Windows in JDK5.0 so don't abort if ZIP_Close is NULL 1.26 - if (ZipOpen == NULL || FindEntry == NULL || ReadEntry == NULL || GetNextEntry == NULL) { 1.27 + if (ZipOpen == NULL || FindEntry == NULL || ReadEntry == NULL || 1.28 + GetNextEntry == NULL || Crc32 == NULL) { 1.29 vm_exit_during_initialization("Corrupted ZIP library", path); 1.30 } 1.31 1.32 @@ -644,6 +648,11 @@ 1.33 // This lookup only works on 1.3. Do not check for non-null here 1.34 } 1.35 1.36 +int ClassLoader::crc32(int crc, const char* buf, int len) { 1.37 + assert(Crc32 != NULL, "ZIP_CRC32 is not found"); 1.38 + return (*Crc32)(crc, (const jbyte*)buf, len); 1.39 +} 1.40 + 1.41 // PackageInfo data exists in order to support the java.lang.Package 1.42 // class. A Package object provides information about a java package 1.43 // (version, vendor, etc.) which originates in the manifest of the jar
2.1 --- a/src/share/vm/classfile/classLoader.hpp Fri Aug 08 15:15:52 2014 -0700 2.2 +++ b/src/share/vm/classfile/classLoader.hpp Tue Aug 12 17:46:16 2014 -0400 2.3 @@ -215,6 +215,7 @@ 2.4 // to avoid confusing the zip library 2.5 static bool get_canonical_path(char* orig, char* out, int len); 2.6 public: 2.7 + static int crc32(int crc, const char* buf, int len); 2.8 // Used by the kernel jvm. 2.9 static void update_class_path_entry_list(char *path, 2.10 bool check_for_duplicates);
3.1 --- a/src/share/vm/memory/filemap.cpp Fri Aug 08 15:15:52 2014 -0700 3.2 +++ b/src/share/vm/memory/filemap.cpp Tue Aug 12 17:46:16 2014 -0400 3.3 @@ -177,7 +177,14 @@ 3.4 fail_continue("The shared archive file has the wrong version."); 3.5 return false; 3.6 } 3.7 - _file_offset = (long)n; 3.8 + size_t len = lseek(fd, 0, SEEK_END); 3.9 + struct FileMapInfo::FileMapHeader::space_info* si = 3.10 + &_header._space[MetaspaceShared::mc]; 3.11 + if (si->_file_offset >= len || len - si->_file_offset < si->_used) { 3.12 + fail_continue("The shared archive file has been truncated."); 3.13 + return false; 3.14 + } 3.15 + _file_offset = n; 3.16 return true; 3.17 } 3.18 3.19 @@ -268,6 +275,7 @@ 3.20 si->_capacity = capacity; 3.21 si->_read_only = read_only; 3.22 si->_allow_exec = allow_exec; 3.23 + si->_crc = ClassLoader::crc32(0, base, (jint)size); 3.24 write_bytes_aligned(base, (int)size); 3.25 } 3.26 3.27 @@ -292,14 +300,15 @@ 3.28 // Align file position to an allocation unit boundary. 3.29 3.30 void FileMapInfo::align_file_position() { 3.31 - long new_file_offset = align_size_up(_file_offset, os::vm_allocation_granularity()); 3.32 + size_t new_file_offset = align_size_up(_file_offset, 3.33 + os::vm_allocation_granularity()); 3.34 if (new_file_offset != _file_offset) { 3.35 _file_offset = new_file_offset; 3.36 if (_file_open) { 3.37 // Seek one byte back from the target and write a byte to insure 3.38 // that the written file is the correct length. 3.39 _file_offset -= 1; 3.40 - if (lseek(_fd, _file_offset, SEEK_SET) < 0) { 3.41 + if (lseek(_fd, (long)_file_offset, SEEK_SET) < 0) { 3.42 fail_stop("Unable to seek.", NULL); 3.43 } 3.44 char zero = 0; 3.45 @@ -406,6 +415,19 @@ 3.46 return base; 3.47 } 3.48 3.49 +bool FileMapInfo::verify_region_checksum(int i) { 3.50 + if (!VerifySharedSpaces) { 3.51 + return true; 3.52 + } 3.53 + const char* buf = _header._space[i]._base; 3.54 + size_t sz = _header._space[i]._used; 3.55 + int crc = ClassLoader::crc32(0, buf, (jint)sz); 3.56 + if (crc != _header._space[i]._crc) { 3.57 + fail_continue("Checksum verification failed."); 3.58 + return false; 3.59 + } 3.60 + return true; 3.61 +} 3.62 3.63 // Unmap a memory region in the address space. 3.64 3.65 @@ -457,8 +479,20 @@ 3.66 return true; 3.67 } 3.68 3.69 +int FileMapInfo::compute_header_crc() { 3.70 + char* header = (char*)&_header; 3.71 + // start computing from the field after _crc 3.72 + char* buf = (char*)&_header._crc + sizeof(int); 3.73 + size_t sz = sizeof(FileMapInfo::FileMapHeader) - (buf - header); 3.74 + int crc = ClassLoader::crc32(0, buf, (jint)sz); 3.75 + return crc; 3.76 +} 3.77 3.78 bool FileMapInfo::validate() { 3.79 + if (VerifySharedSpaces && compute_header_crc() != _header._crc) { 3.80 + fail_continue("Header checksum verification failed."); 3.81 + return false; 3.82 + } 3.83 if (_header._version != current_version()) { 3.84 fail_continue("The shared archive file is the wrong version."); 3.85 return false;
4.1 --- a/src/share/vm/memory/filemap.hpp Fri Aug 08 15:15:52 2014 -0700 4.2 +++ b/src/share/vm/memory/filemap.hpp Tue Aug 12 17:46:16 2014 -0400 4.3 @@ -54,7 +54,7 @@ 4.4 4.5 bool _file_open; 4.6 int _fd; 4.7 - long _file_offset; 4.8 + size_t _file_offset; 4.9 4.10 // FileMapHeader describes the shared space data in the file to be 4.11 // mapped. This structure gets written to a file. It is not a class, so 4.12 @@ -62,12 +62,14 @@ 4.13 4.14 struct FileMapHeader { 4.15 int _magic; // identify file type. 4.16 + int _crc; // header crc checksum. 4.17 int _version; // (from enum, above.) 4.18 size_t _alignment; // how shared archive should be aligned 4.19 int _obj_alignment; // value of ObjectAlignmentInBytes 4.20 4.21 struct space_info { 4.22 - int _file_offset; // sizeof(this) rounded to vm page size 4.23 + int _crc; // crc checksum of the current space 4.24 + size_t _file_offset; // sizeof(this) rounded to vm page size 4.25 char* _base; // copy-on-write base address 4.26 size_t _capacity; // for validity checking 4.27 size_t _used; // for setting space top on read 4.28 @@ -104,6 +106,8 @@ 4.29 } 4.30 4.31 static int current_version() { return _current_version; } 4.32 + int compute_header_crc(); 4.33 + void set_header_crc(int crc) { _header._crc = crc; } 4.34 void populate_header(size_t alignment); 4.35 bool validate(); 4.36 void invalidate(); 4.37 @@ -136,6 +140,7 @@ 4.38 void write_bytes_aligned(const void* buffer, int count); 4.39 char* map_region(int i); 4.40 void unmap_region(int i); 4.41 + bool verify_region_checksum(int i); 4.42 void close(); 4.43 bool is_open() { return _file_open; } 4.44 ReservedSpace reserve_shared_memory();
5.1 --- a/src/share/vm/memory/metaspaceShared.cpp Fri Aug 08 15:15:52 2014 -0700 5.2 +++ b/src/share/vm/memory/metaspaceShared.cpp Tue Aug 12 17:46:16 2014 -0400 5.3 @@ -585,6 +585,7 @@ 5.4 5.5 // Pass 2 - write data. 5.6 mapinfo->open_for_write(); 5.7 + mapinfo->set_header_crc(mapinfo->compute_header_crc()); 5.8 mapinfo->write_header(); 5.9 mapinfo->write_space(MetaspaceShared::ro, _loader_data->ro_metaspace(), true); 5.10 mapinfo->write_space(MetaspaceShared::rw, _loader_data->rw_metaspace(), false); 5.11 @@ -863,9 +864,13 @@ 5.12 5.13 // Map each shared region 5.14 if ((_ro_base = mapinfo->map_region(ro)) != NULL && 5.15 + mapinfo->verify_region_checksum(ro) && 5.16 (_rw_base = mapinfo->map_region(rw)) != NULL && 5.17 + mapinfo->verify_region_checksum(rw) && 5.18 (_md_base = mapinfo->map_region(md)) != NULL && 5.19 + mapinfo->verify_region_checksum(md) && 5.20 (_mc_base = mapinfo->map_region(mc)) != NULL && 5.21 + mapinfo->verify_region_checksum(mc) && 5.22 (image_alignment == (size_t)max_alignment())) { 5.23 // Success (no need to do anything) 5.24 return true;
6.1 --- a/src/share/vm/runtime/arguments.cpp Fri Aug 08 15:15:52 2014 -0700 6.2 +++ b/src/share/vm/runtime/arguments.cpp Tue Aug 12 17:46:16 2014 -0400 6.3 @@ -3581,6 +3581,11 @@ 6.4 return JNI_ENOMEM; 6.5 } 6.6 6.7 + // Set up VerifySharedSpaces 6.8 + if (FLAG_IS_DEFAULT(VerifySharedSpaces) && SharedArchiveFile != NULL) { 6.9 + VerifySharedSpaces = true; 6.10 + } 6.11 + 6.12 // Delay warning until here so that we've had a chance to process 6.13 // the -XX:-PrintWarnings flag 6.14 if (needs_hotspotrc_warning) {
7.1 --- a/src/share/vm/runtime/globals.hpp Fri Aug 08 15:15:52 2014 -0700 7.2 +++ b/src/share/vm/runtime/globals.hpp Tue Aug 12 17:46:16 2014 -0400 7.3 @@ -3745,6 +3745,10 @@ 7.4 product(bool, UseSharedSpaces, true, \ 7.5 "Use shared spaces for metadata") \ 7.6 \ 7.7 + product(bool, VerifySharedSpaces, false, \ 7.8 + "Verify shared spaces (false for default archive, true for " \ 7.9 + "archive specified by -XX:SharedArchiveFile)") \ 7.10 + \ 7.11 product(bool, RequireSharedSpaces, false, \ 7.12 "Require shared spaces for metadata") \ 7.13 \