8161224: CONSTANT_NameAndType_info permits references to illegal names and descriptors
authorrprotacio
Tue, 06 Sep 2016 16:29:32 -0400
changeset 40920 8fcd156236e6
parent 40659 a2b2936240b9
child 40921 cc129ac8e609
8161224: CONSTANT_NameAndType_info permits references to illegal names and descriptors Summary: Enforces proper format checking for NameAndType string content, and that the checking occurs even when not referenced in classfile Reviewed-by: coleenp, hseigel, ddmitriev
hotspot/src/share/vm/classfile/classFileParser.cpp
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp	Mon Aug 22 15:54:22 2016 +0000
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp	Tue Sep 06 16:29:32 2016 -0400
@@ -95,7 +95,6 @@
 #define JAVA_6_VERSION                    50
 
 // Used for backward compatibility reasons:
-// - to check NameAndType_info signatures more aggressively
 // - to disallow argument and require ACC_STATIC for <clinit> methods
 #define JAVA_7_VERSION                    51
 
@@ -564,7 +563,7 @@
         break;
       }
       case JVM_CONSTANT_NameAndType: {
-        if (_need_verify && _major_version >= JAVA_7_VERSION) {
+        if (_need_verify) {
           const int sig_index = cp->signature_ref_index_at(index);
           const int name_index = cp->name_ref_index_at(index);
           const Symbol* const name = cp->symbol_at(name_index);
@@ -572,9 +571,17 @@
           guarantee_property(sig->utf8_length() != 0,
             "Illegal zero length constant pool entry at %d in class %s",
             sig_index, CHECK);
+          guarantee_property(name->utf8_length() != 0,
+            "Illegal zero length constant pool entry at %d in class %s",
+            name_index, CHECK);
+
           if (sig->byte_at(0) == JVM_SIGNATURE_FUNC) {
+            // Format check method name and signature
+            verify_legal_method_name(name, CHECK);
             verify_legal_method_signature(name, sig, CHECK);
           } else {
+            // Format check field name and signature
+            verify_legal_field_name(name, CHECK);
             verify_legal_field_signature(name, sig, CHECK);
           }
         }
@@ -595,42 +602,32 @@
         const Symbol* const name = cp->symbol_at(name_ref_index);
         const Symbol* const signature = cp->symbol_at(signature_ref_index);
         if (tag == JVM_CONSTANT_Fieldref) {
-          verify_legal_field_name(name, CHECK);
-          if (_need_verify && _major_version >= JAVA_7_VERSION) {
-            // Signature is verified above, when iterating NameAndType_info.
-            // Need only to be sure it's non-zero length and the right type.
+          if (_need_verify) {
+            // Field name and signature are verified above, when iterating NameAndType_info.
+            // Need only to be sure signature is non-zero length and the right type.
             if (signature->utf8_length() == 0 ||
                 signature->byte_at(0) == JVM_SIGNATURE_FUNC) {
-              throwIllegalSignature(
-                "Field", name, signature, CHECK);
+              throwIllegalSignature("Field", name, signature, CHECK);
             }
-          } else {
-            verify_legal_field_signature(name, signature, CHECK);
           }
         } else {
-          verify_legal_method_name(name, CHECK);
-          if (_need_verify && _major_version >= JAVA_7_VERSION) {
-            // Signature is verified above, when iterating NameAndType_info.
-            // Need only to be sure it's non-zero length and the right type.
+          if (_need_verify) {
+            // Method name and signature are verified above, when iterating NameAndType_info.
+            // Need only to be sure signature is non-zero length and the right type.
             if (signature->utf8_length() == 0 ||
                 signature->byte_at(0) != JVM_SIGNATURE_FUNC) {
-              throwIllegalSignature(
-                "Method", name, signature, CHECK);
+              throwIllegalSignature("Method", name, signature, CHECK);
             }
-          } else {
-            verify_legal_method_signature(name, signature, CHECK);
           }
-          if (tag == JVM_CONSTANT_Methodref) {
-            // 4509014: If a class method name begins with '<', it must be "<init>".
-            assert(name != NULL, "method name in constant pool is null");
-            const unsigned int name_len = name->utf8_length();
-            if (name_len != 0 && name->byte_at(0) == '<') {
-              if (name != vmSymbols::object_initializer_name()) {
-                classfile_parse_error(
-                  "Bad method name at constant pool index %u in class file %s",
-                  name_ref_index, CHECK);
-              }
-            }
+          // 4509014: If a class method name begins with '<', it must be "<init>"
+          const unsigned int name_len = name->utf8_length();
+          if (tag == JVM_CONSTANT_Methodref &&
+              name_len != 0 &&
+              name->byte_at(0) == '<' &&
+              name != vmSymbols::object_initializer_name()) {
+            classfile_parse_error(
+              "Bad method name at constant pool index %u in class file %s",
+              name_ref_index, CHECK);
           }
         }
         break;
@@ -4843,19 +4840,28 @@
         }
       }
       else {
-        // 4900761: For class version > 48, any unicode is allowed in class name.
+        // Skip leading 'L' and ignore first appearance of ';'
         length--;
         signature++;
-        while (length > 0 && signature[0] != ';') {
-          if (signature[0] == '.') {
-            classfile_parse_error("Class name contains illegal character '.' in descriptor in class file %s", CHECK_0);
+        char* c = strchr((char*) signature, ';');
+        // Format check signature
+        if (c != NULL) {
+          ResourceMark rm(THREAD);
+          int newlen = c - (char*) signature;
+          char* sig = NEW_RESOURCE_ARRAY(char, newlen + 1);
+          strncpy(sig, signature, newlen);
+          sig[newlen] = '\0';
+
+          bool legal = verify_unqualified_name(sig, newlen, LegalClass);
+          if (!legal) {
+            classfile_parse_error("Class name contains illegal character "
+                                  "in descriptor in class file %s",
+                                  CHECK_0);
+            return NULL;
           }
-          length--;
-          signature++;
+          return signature + newlen + 1;
         }
-        if (signature[0] == ';') { return signature + 1; }
       }
-
       return NULL;
     }
     case JVM_SIGNATURE_ARRAY:
@@ -4869,7 +4875,6 @@
       length--;
       void_ok = false;
       break;
-
     default:
       return NULL;
     }