1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.bcel.verifier.statics; 18 19 import org.apache.bcel.Repository; 20 import org.apache.bcel.classfile.ClassFormatException; 21 import org.apache.bcel.classfile.JavaClass; 22 import org.apache.bcel.verifier.PassVerifier; 23 import org.apache.bcel.verifier.VerificationResult; 24 import org.apache.bcel.verifier.Verifier; 25 import org.apache.bcel.verifier.exc.LoadingException; 26 import org.apache.commons.lang3.ArrayUtils; 27 28 /** 29 * This PassVerifier verifies a class file according to pass 1 as described in The Java Virtual Machine Specification, 30 * 2nd edition. More detailed information is to be found at the do_verify() method's documentation. 31 * 32 * @see #do_verify() 33 */ 34 public final class Pass1Verifier extends PassVerifier { 35 /** 36 * DON'T USE THIS EVEN PRIVATELY! USE getJavaClass() INSTEAD. 37 * 38 * @see #getJavaClass() 39 */ 40 private JavaClass javaClass; 41 42 /** 43 * The Verifier that created this. 44 */ 45 private final Verifier verifier; 46 47 /** 48 * Should only be instantiated by a Verifier. 49 * 50 * @see Verifier 51 */ 52 public Pass1Verifier(final Verifier verifier) { 53 this.verifier = verifier; 54 } 55 56 /** 57 * Pass-one verification basically means loading in a class file. The Java Virtual Machine Specification is not too 58 * precise about what makes the difference between passes one and two. The answer is that only pass one is performed on 59 * a class file as long as its resolution is not requested; whereas pass two and pass three are performed during the 60 * resolution process. Only four constraints to be checked are explicitly stated by The Java Virtual Machine 61 * Specification, 2nd edition: 62 * <UL> 63 * <LI>The first four bytes must contain the right magic number (0xCAFEBABE). 64 * <LI>All recognized attributes must be of the proper length. 65 * <LI>The class file must not be truncated or have extra bytes at the end. 66 * <LI>The constant pool must not contain any superficially unrecognizable information. 67 * </UL> 68 * A more in-depth documentation of what pass one should do was written by <A HREF=mailto:pwfong@cs.sfu.ca>Philip W. L. 69 * Fong</A>: 70 * <UL> 71 * <LI>the file should not be truncated. 72 * <LI>the file should not have extra bytes at the end. 73 * <LI>all variable-length structures should be well-formatted: 74 * <UL> 75 * <LI>there should only be constant_pool_count-1 many entries in the constant pool. 76 * <LI>all constant pool entries should have size the same as indicated by their type tag. 77 * <LI>there are exactly interfaces_count many entries in the interfaces array of the class file. 78 * <LI>there are exactly fields_count many entries in the fields array of the class file. 79 * <LI>there are exactly methods_count many entries in the methods array of the class file. 80 * <LI>there are exactly attributes_count many entries in the attributes array of the class file, fields, methods, and 81 * code attribute. 82 * <LI>there should be exactly attribute_length many bytes in each attribute. Inconsistency between attribute_length and 83 * the actually size of the attribute content should be uncovered. For example, in an Exceptions attribute, the actual 84 * number of exceptions as required by the number_of_exceptions field might yeild an attribute size that doesn't match 85 * the attribute_length. Such an anomaly should be detected. 86 * <LI>all attributes should have proper length. In particular, under certain context (e.g. while parsing method_info), 87 * recognizable attributes (e.g. "Code" attribute) should have correct format (e.g. attribute_length is 2). 88 * </UL> 89 * <LI>Also, certain constant values are checked for validity: 90 * <UL> 91 * <LI>The magic number should be 0xCAFEBABE. 92 * <LI>The major and minor version numbers are valid. 93 * <LI>All the constant pool type tags are recognizable. 94 * <LI>All undocumented access flags are masked off before use. Strictly speaking, this is not really a check. 95 * <LI>The field this_class should point to a string that represents a legal non-array class name, and this name should 96 * be the same as the class file being loaded. 97 * <LI>the field super_class should point to a string that represents a legal non-array class name. 98 * <LI>Because some of the above checks require cross referencing the constant pool entries, guards are set up to make 99 * sure that the referenced entries are of the right type and the indices are within the legal range (0 < index < 100 * constant_pool_count). 101 * </UL> 102 * <LI>Extra checks done in pass 1: 103 * <UL> 104 * <LI>the constant values of static fields should have the same type as the fields. 105 * <LI>the number of words in a parameter list does not exceed 255 and locals_max. 106 * <LI>the name and signature of fields and methods are verified to be of legal format. 107 * </UL> 108 * </UL> 109 * (From the Paper <A HREF="http://www.cs.sfu.ca/people/GradStudents/pwfong/personal/JVM/pass1/"> The Mysterious Pass 110 * One, first draft, September 2, 1997</A>.) 111 * 112 * <P> 113 * However, most of this is done by parsing a class file or generating a class file into BCEL's internal data structure. 114 * <B>Therefore, all that is really done here is look up the class file from BCEL's repository.</B> This is also 115 * motivated by the fact that some omitted things (like the check for extra bytes at the end of the class file) are 116 * handy when actually using BCEL to repair a class file (otherwise you would not be able to load it into BCEL). 117 * </P> 118 * 119 * @see org.apache.bcel.Repository 120 * @see org.apache.bcel.Const#JVM_CLASSFILE_MAGIC 121 */ 122 @Override 123 public VerificationResult do_verify() { 124 JavaClass jc; 125 try { 126 jc = getJavaClass(); // loads in the class file if not already done. 127 128 /* If we find more constraints to check, we should do this in an own method. */ 129 // This should maybe caught by BCEL: In case of renamed .class files we get wrong 130 // JavaClass objects here. 131 // This test should be much more complicated. It needs to take the class name, remove any portion at the 132 // end that matches the file name and then see if the remainder matches anything on the class path. 133 // Dumb test for now, see if the class name ends with the file name. 134 if (jc != null && !verifier.getClassName().equals(jc.getClassName()) && !jc.getClassName().endsWith(verifier.getClassName())) { 135 throw new LoadingException("Wrong name: the internal name of the .class file '" + jc.getClassName() + "' does not match the file's name '" 136 + verifier.getClassName() + "'."); 137 } 138 } catch (final LoadingException | ClassFormatException e) { 139 return new VerificationResult(VerificationResult.VERIFIED_REJECTED, e.getMessage()); 140 } catch (final RuntimeException e) { 141 // BCEL does not catch every possible RuntimeException; e.g. if 142 // a constant pool index is referenced that does not exist. 143 return new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Parsing via BCEL did not succeed. " + " exception occurred:\n" + e.toString()); 144 // Don't think we want to dump a stack trace unless we have some sort of a debug option. 145 // e.getClass().getName()+" occurred:\n"+Utility.getStackTrace(e)); 146 } 147 148 if (jc != null) { 149 return VerificationResult.VR_OK; 150 } 151 // TODO: Maybe change Repository's behavior to throw a LoadingException instead of just returning "null" 152 // if a class file cannot be found or in another way be looked up. 153 return new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Repository.lookup() failed. FILE NOT FOUND?"); 154 } 155 156 /** 157 * Used to load in and return the myOwner-matching JavaClass object when needed. Avoids loading in a class file when 158 * it's not really needed! 159 */ 160 private JavaClass getJavaClass() { 161 if (javaClass == null) { 162 try { 163 javaClass = Repository.lookupClass(verifier.getClassName()); 164 } catch (final ClassNotFoundException ignored) { 165 // FIXME: currently, Pass1Verifier treats jc == null as a special 166 // case, so we don't need to do anything here. A better solution 167 // would be to simply throw the ClassNotFoundException 168 // out of this method. 169 } 170 } 171 return javaClass; 172 } 173 174 /** 175 * Currently this returns an empty array of String. One could parse the error messages of BCEL (written to 176 * java.lang.System.err) when loading a class file such as detecting unknown attributes or trailing garbage at the end 177 * of a class file. However, Markus Dahm does not like the idea so this method is currently useless and therefore marked 178 * as <b>TODO</b>. 179 */ 180 @Override 181 public String[] getMessages() { 182 return ArrayUtils.EMPTY_STRING_ARRAY; 183 } 184 185 }