flects the intentions of the source code
and at the same time maintains the inherent properties of the Java language,
such as type safety. A maliciously generated sequence of bytecode, on the other
hand, may not correspond to any valid
Java source code at all and can intentionally break language properties in
order to enable security attacks.
Telling whether a presented series
opcode is “valid” is fundamentally a
form of the input validation problem.
Suppose the JVM takes any integer in the
range of 1 to 9 as valid input; then input
validation is trivial. In reality, the input
space that contains arbitrary sequences of opcode is unlimited in size and
sparsely populated with valid bytecode
sequences. Because there is no simple
validation test formula through which
to run a target code, the Java runtime
system does bytecode validation in multiple stages, with various techniques, at
different places. The bytecode verifier
statically checks incoming code. Once
the code is inside the system, type-safety
mechanisms are deployed throughout
the JVM to spot and stop illegitimate
code. All these maneuvers are complex,
and, in the absence of formal verification of the total system, there is no way
to know for sure that all possible invalid
codes can be spotted.
Thus, one really hard problem for
any runtime system that deals with
executable code compiled from high-level languages is to ensure that code
received from “foreign” sources is valid
input. For most programming languages, this is simply not possible. Java’s
platform-independent bytecode makes
this task possible, but it is still extremely
difficult to get right. Brian Bershad and
his (then) student Emin Gun Sirer at the
University of Washington came up with
the concept of a bytecode basher.
4 They
set up an automated system to generate
random sequences of opcode to throw
at any particular Java runtime system;
they watch to see if the system breaks
and then analyze the results to figure
out the flaws in the Java implementation. This randomized and automated
approach is a surprisingly low-cost yet
effective tool that the JavaSoft team
quickly adopted.
Who moved my cheese?
Now comes the problem of preventing
bad unintended behavior. For example,
when a Java application or applet trig-
gers an access request for a local file,
should the request be granted? Well, it
depends. If the request is to read the lo-
cal file containing personal credit card
information, then the request may or
may not be granted, depending on if
there is a security policy or user prefer-
ence in place. If the request is to read
the font file for 12-point Calibri type so
that a text file can be displayed accord-
ing to the word processor specification,
then it almost always should be grant-
ed, because, implicitly, font files are
structured to be harmless if used in this
fashion. Note that applications never di-
rectly open files. They call the file APIs
in the Java platform for these opera-
tions. These APIs have no built-in no-
tion of security, except that they (or their
designers) know that file operations are
sensitive, so they better make a call to
the SecurityManager for consultation.