Click Here!
home account info subscribe login search My ITKnowledge FAQ/help site map contact us


 
Brief Full
 Advanced
      Search
 Search Tips
To access the contents, click the chapter and section titles.

Platinum Edition Using HTML 4, XML, and Java 1.2
(Publisher: Macmillan Computer Publishing)
Author(s): Eric Ladd
ISBN: 078971759x
Publication Date: 11/01/98

Bookmark It

Search this book:
 
Previous Table of Contents Next


The JVM instruction set provides opcodes that operate on various data types and can be divided into several categories:

  Pushing constants onto the stack
  Accessing and modifying the value of a register
  Accessing arrays
  Stack manipulation
  Arithmetic, logical, and conversion instructions
  Control transfer
  Function return
  Manipulating object fields
  Method invocation
  Object creation
  Type casting

The bytecodes consist of a one-byte opcode followed by zero or more bytes of additional operand information. With two exceptions, all instructions are fixed length and based on the opcode.

The Bytecode Verifier

The bytecode verifier is the last line of defense against a bad Java applet. This is where the classes are checked for integrity, where the compiled code is checked for its adherence to the Java rules, and where a misbehaving applet is most likely caught. If the compiled code was created with a “fixed” compiler to get around Java’s restrictions, it will still fail the verifier’s checks and be stopped. The bytecode verifier is one of the most interesting parts of the Java security mechanism because of the way it is designed to be thorough and general at the same time. The bytecode verifier does not have to work only on code created by a Java compiler, but on any bytecodes created for a JVM, so it needs to be general. However, it also needs to catch all exceptions to the rules laid out for a Java applet or application and must, therefore, be thorough.

All bytecode goes through the bytecode verifier, which makes four passes over the code.

Pass 1 is the most basic pass. The verifier makes sure that the following criteria are met:

  The .class file conforms to the format of a .class file.
  The magic constant at the beginning is correct.
  All attributes are of the proper length.
  The .class file does not have any extra bytes, nor too few.
  The constant pool does not have any unrecognized information.

Pass 1 finds any corrupt .class files from a faulty compiler and also catches .class files that were damaged in transit. Assuming everything goes well, you get to the second pass.

Pass 2 adds a little more scrutiny. It verifies almost everything without actually looking at the bytecodes themselves. Some of the things that Pass 2 is responsible for are

  Ensuring that final classes are not subclassed and that final methods are not overridden
  Checking that every class (except Object) has a superclass
  Ensuring that the constant pool meets certain constraints
  Checking that all field references and methods in the constant pool have legal names, classes, and a type signature

On Pass 2, everything needs to look legal—that is, at face value all the classes appear to refer to classes that really exist, rules of inheritance aren’t broken, and so on. It does not check the bytecodes themselves; this task is left up to further passes. Passes 3 and 4 check to see if the fields and methods actually exist in a real class and if the types refer to real classes.

On Pass 3, the actual bytecodes of each method are verified. Each method undergoes dataflow analysis to ensure that the following things are true:

  The stack is always the same size and contains the same types of objects.
  No registers are accessed unless they are known to contain values of a specific type.
  All methods are called with the correct arguments.
  All opcodes have appropriate type arguments on the stack and in the registers.
  Fields are modified with values of the appropriate type.

The verifier ensures that the exception handler offsets point to legitimate starting and ending offsets in the code. It also makes sure the code does not end in the middle of an instruction.

Pass 4 occurs as the code actually runs. During Pass 3, the bytecode verifier does not load any classes unless it must to check its validity. This approach makes the bytecode verifier more efficient. On Pass 4, the final checks are made the first time an instruction referencing a class executes. The verifier then does the following:

  Loads in the definition of the class (if not already loaded)
  Verifies that the currently executing class is allowed to reference the given class

Likewise, the first time an instruction calls a method or accesses or modifies a field, the verifier does the following:

  Ensures that the method or field exists in the given class
  Checks that the method or field has the indicated signature
  Checks that the currently executing method has access to the given method or field

Namespace Encapsulation Using Packages

Java classes are defined within packages that give them unique names. The Java standard for naming packages is the domain the package originates from, but in reverse order with the first part capitalized. If your domain is www.yourdomain.com, your classes should be in the COM.yourdomain.www package.

What is the advantage to using packages? With packages, a class arriving over the network is distinguishable, and therefore, cannot impersonate a trusted local class.

Runtime Linking and Binding

The exact layout of runtime resources is one of the last things done by the JVM. Java uses dynamic linking—linking and binding during runtime. This technique prevents an unscrupulous programmer from making assumptions about the allocation of resources or utilizing this information to attack security.

Security in the Java Runtime System

Classes can be treated differently when loaded locally, in contrast to over a network. One of these differences is how the class is loaded into the runtime system. The default way for this to happen is to load the class from a local .class file. Any other way of retrieving a class requires the class to be loaded with an associated ClassLoader. The ClassLoader class is a subtype of a standard Java object that has the methods to implement many of the security mechanisms we have discussed so far. A lot of the attack scenarios that have been used against Java have involved getting around the ClassLoader.

The ClassLoader comes into play after Pass 3 of the bytecode verifier as the classes are actually loaded on Pass 4. The ClassLoader is fairly generic because it does not know for certain that it is loading classes written in Java. It could be loading classes written in C++ and compiled into bytecode.

The ClassLoader, therefore, has to check general rules for consistency within ClassFiles. If a class fails these checks, it isn’t loaded and an attack on an end user’s system fails. It is an important part of the Java security system.


Previous Table of Contents Next


Products |  Contact Us |  About Us |  Privacy  |  Ad Info  |  Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc.
All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.