Bytecode Verification and Security

In most cases, all classes loaded by a JVM are subject to a process called
``bytecode verification''. This verification is done to ensure that
classes do not perform operations that may cause the JVM to crash. The
verification process checks that all arguments on the operand stack are
legal. In addition, the verifier ensures that all types of all variables
passed to methods are correct, and that all load and store operations have
correct types.

To accomplish this task, the verifier must do extensive analysis on the
JVM code. This analysis is briefly summarized in [17, pages 128-130]. The analysis is
discussed in detail in [11,12,13]. The details of this verification
analysis are somewhat beyond the scope of this thesis; however, details
are mentioned later in those cases that impact this work directly.

Of course, this verification analysis introduces overhead. The argument
is made, though, that this overhead is worthwhile, since JVM code
execution can afterwards proceed more quickly without checking types and
stack limits. For such quick execution to take place, the JVM must assume
that the verifier has checked all these parameters. In addition, the
execution process must assume that verification rejects invalid code
constructed with malicious intent.

However, bytecode verification is not without disadvantages. The verifier
can limit some otherwise valid uses of the JVM. In fact, the first
approach used in this project was impeded (and eventually rendered futile)
because code was generated that could not pass the verification.
Section 4.5 discusses
this problem in detail.

Note that JVM bytecode verification is only a subset of those checks
performed when an ``applet'' is loaded from the network. In those cases,
more extensive checks are done to ensure that access to the local
operating system is severely limited.