`
`Ajay Chander
`Computer Science Department
`Stanford University
`ajayc@cs.stanford.edu
`
`John C. Mitchell
`Computer Science Department
`Stanford University
`mitchell@cs.stanford.edu
`
`Insik Shin
`Department of Computer and Information Science
`University of Pennsylvania
`ishin@cis.upenn.edu
`
`Abstract
`
`Mobile code provides significant opportunities and risks.
`Java bytecode is used to provide executable content to web
`pages and is the basis for dynamic service configuration
`in the Jini framework. While the Java Virtual Machine in-
`cludes a bytecode verifier that checks bytecode programs
`before execution, and a bytecode interpreter that performs
`run-time tests, mobile code may still behave in ways that
`are harmful to users. We present techniques that insert run-
`time tests into Java code, illustrating them for Java applets
`and Jini proxy bytecodes. These techniques may be used
`to contain mobile code behavior or, potentially, insert code
`appropriate to profiling or other monitoring efforts. The
`main techniques are class modification, involving subclass-
`ing non-final classes, and method-level modifications that
`may be used when control over objects from final classes is
`desired.
`
`1. Introduction
`
`Since its early beginnings in the Green project, the Java
`language [26] has come a long way in its applicability and
`prevalence. While its initial adoption was fuelled by the
`ability to add “active content” to web pages, Java has also
`become a predominant system and application development
`language, providing useful capabilities over and above the
`language features through an extensive set of application
`programming interfaces (APIs). The APIs simplify pro-
`gramming by providing a rich set of domain-dependent li-
`braries, as well as enabling new programmatic and compu-
`tational paradigms. As an example, the Java Cryptography
` Partially supported by DARPA contract N66001-00-C-8015 and ONR
`grant N00014-97-1-0505.
`
`API makes it possible for applications to easily implement
`security protocols for their own needs, while the Jini API
`provides a specification for Java bytecode based distributed
`programming. One of the keys to Java’s success and appeal
`is its platform independence, achieved by compilation of
`source code to a common intermediate format, namely Java
`Virtual Machine (JVM) bytecode, which can then be inter-
`preted by various platforms. The ability to transport byte-
`code between JVMs is most commonly encountered while
`browsing the net, and Java’s platform independence ensures
`a client-independent experience.
`Although previous language implementations, such as
`Pascal and Smalltalk systems, have used intermediate byte-
`code, the use of bytecode as a medium of exchange places
`Java bytecode in a new light. A networked computer can
`import and execute Java bytecode in ways that are invisi-
`ble or partly invisible to the user. For example, a user (or
`his browser) may execute a Java applet embedded within a
`page as part of the HTTP protocol, or a client may execute a
`lookup service proxy as it prepares to join a Jini community.
`To protect against execution of erroneous or intentionally
`malicious code, the JVM verifies bytecode properties be-
`fore execution and performs additional checks at run time.
`However, these checks only enforce some type correctness
`conditions and basic resource access control. For example,
`these tests will not protect against large classes of undesir-
`able run-time behavior, including denial-of-service, com-
`promise of integrity, and loss of sensitive information from
`password or credit card information files, say. The introduc-
`tion of new security architectures [8] for Java has allowed
`for digital signature verification and resource access control
`through the Permissions framework, but suffers from lack
`of specificity. A more expressive and fine-grained mech-
`anism which can be customized to a user’s security needs
`and is flexible enough to respond to security holes as they
`
`Juniper Ex. 1008-p. 1
`Juniper v Finjan
`
`
`
`are discovered, is needed.
`The goal of our work is to develop methods for enforc-
`ing foreign bytecode properties, in a manner that may be
`customized easily. In this paper, we propose a technique,
`called bytecode instrumentation, through which we impose
`restrictions on bytecode by inserting additional instructions
`that will perform the necessary run-time tests. These ad-
`ditional instructions may monitor and control resource us-
`age as well as limit code functionality. This approach is
`essentially a form of software fault isolation [24], tailored
`to the file structure and commands of the Java language.
`Our technique falls into two parts: class-level modification
`and method-level modification. Class-level modification in-
`volves substituting references to a class by another class
`subclassed from it. As this method employs inheritance,
`it can not be applied to final classes and interfaces. In these
`cases, method-level modification, which may be applied on
`a method-by-method basis without regard to class hierarchy
`restrictions, enforces the safe behavior that we hope from
`foreign code.
`We have implemented these techniques within two con-
`texts, each of which has a different bytecode delivery path.
`For the case of Java applets transported via the HTTP pro-
`tocol, instrumentation is done by a network proxy, which in
`addition can also function as a GUI-customizable firewall
`to specific sites, Java classes, and tagged advertisements.
`For Jini service proxies, for which there are only transport
`interfaces but no specific transport mechanisms, we chose
`to modify the bytecode at the client’s ClassLoader end, be-
`fore its execution. Figures 5 and 6 summarize the system
`architecture for these two cases.
`The rest of the paper is organized as follows. Section
`2 gives examples of mobile code risks which cannot be
`checked within the scope of the current Java verifier and
`security model, and discusses the extent of our technique.
`The bytecode instrumentation technique itself is presented
`in Section 3. Section 4 explains how the mobile code trans-
`port frameworks for Java applets and Jini proxies are aug-
`mented to instrument the component bytecodes. Section 5
`presents examples of the techniques presented in Section
`3, with one illustrative example for each of class-level and
`method-level modification. We make comparisons with ex-
`isting work in Section 6, and conclude in Section 7.
`
`2. Mobile Code Risks
`
`We preface our techniques for enforcing Java bytecode
`properties by examples of harmful behavior to illustrate the
`risk associated with untrusted mobile code. While these at-
`tacks have been around for a while, recent interest in peer to
`peer computing has added value to individual machine cy-
`cles, and one may presume, incentive to deploying mobile
`code attacks.
`
`The categorisations below should be taken only as in-
`dicative, and not exhaustive. We situate the extent of our
`techniques w.r.t.
`the various kinds of attack threats posed
`by mobile code; Section 5 presents more detail for specific
`examples.
`
`2.1. Denial of Service
`
`The current Java security model provides a Permissions
`framework to specify the host resources that mobile code
`may access. However, the extent of use is not monitored,
`and code which has legitimate use for a certain resource,
`say the screen, or the audio driver, may abuse this privi-
`lege. The system may be rendered useless by greedy tech-
`niques: monopolizing and stealing CPU time, grabbing all
`available system memory, or starving other threads and sys-
`tem processes. Many variants on this theme exist, a com-
`mon scheme is for the foreign code to spawn a “resource
`consuming” thread. The runaway thread redefines its stop
`method to execute a loop and effects an “infinite access” to
`the resource, which may result in annoying to crippling be-
`havior, for example through screen flooding. Often a com-
`plete browser or system shutdown becomes the only viable
`option.
`Since the safety of Java runtime system may be threat-
`ened by inordinate system resource use, it is useful to have
`some mechanism to monitor and control resource usage.
`
`2.2. Information Leaks
`
`An applet may subvert its constrained channels of infor-
`mation flow through various means. A possible third-party
`channel is available with the URL redirect feature. Nor-
`mally, an applet may instruct the browser to load any page
`on the web. An attacker’s server could record the URL as
`a message, then redirect the browser to the original destina-
`tion [5]. Another scenario exploits the ability of an applet to
`send out email messages [10]. If the web server is running
`an SMTP mail daemon, a hostile applet may forge email
`after connecting to port 25.
`Time-delayed access to files also can be used as a covert
`channel [19]. Specifically, if mobile code fragment (cid:0), with
`access to private information is prohibited from accessing
`the net, information can still be sent out by another mo-
`bile code fragment (cid:2), which shares a file with (cid:0). Inter-
`code communication via storage channels may be detected
`by system logs, but these are hard to analyze in real time.
`It is generally accepted that theoretically feasible covert
`channels like refreshing a page at uneven time intervals to
`transmit a sequence of bits, are hard to detect. We ig-
`nore such arbitrary and unpredictable information channels,
`while using our techniques to plug more tractable pathways
`as in the case of email forgery.
`
`Juniper Ex. 1008-p. 2
`Juniper v Finjan
`
`
`
`2.3. Spoofing
`
`In a spoofing attack, an attacker creates a misleading
`context in order to trick a user into making an inappropriate
`security-relevant decision [7]. For example, some applets
`display URLs as the mouse navigates over various compo-
`nents of a web page, like a graphic or a link. By convention,
`the URL is shown in a specific position on the status line. If
`an applet displays a fake URL, the user may be misled into
`connecting to a potentially hazardous website. It is also pos-
`sible to abuse weaknesses in mobile code-fetch conventions
`to spoof the real place of origin of a code fragment, laying
`client-side security policies regarding network connections
`to naught.
`
`Bytecode instrumentation is an effective technique
`against well-specified attacks, which include denial of ser-
`vice and information leaks via specific pathways. In this
`sense, its scope is monotonic; newly discovered attack spec-
`ifications can be added to a client’s policy files and any addi-
`tional bytecodes that match them can be instrumented to en-
`force safety properties. The reader may like to think of this
`in virus checking terms, where the safety net widens with
`addition of new entries in the virus signature files. Byte-
`code instrumentation thus allows for content-based protec-
`tion, since the modification is a function of the bytecode and
`the client’s safety policy.
`We now move on to the technical details of our scheme.
`
`3. Bytecode Instrumentation
`
`Our goal is to design a safety mechanism for Java byte-
`code that extends the signature based security manager with
`user-controlled content-based control. The basic idea is to
`restrict bytecode by the insertion of sentinel code. In the ex-
`amples we have implemented and tested, sentinel code may
`monitor and control resource usage as well as limit func-
`tionality. This approach is a form of software fault isola-
`tion [24], adapted to the specific structure and representa-
`tion of Java bytecode programs.
`Our safety mechanism substitutes one executable entity,
`such as a class or a method, with a related executable en-
`tity that performs additional run-time tests. For instance, a
`class such as Window can be replaced with a more restric-
`tive class Safe$Window that performs additional security
`and sanity checks. This replacement must occur before the
`transported bytecode is loaded within the JVM of the client,
`and we achieve this at different points in the transport path
`in our experiments with Java applets and Jini proxies (see
`Section 4). Note that we will use the prefix Safe$ to indi-
`cate a safe class.
`The following sections explain how modified executable
`entities are inserted in Java bytecode. The modifications
`
`may be performed at the level of the class or the method, by
`modifying the constant pool to replace references to substi-
`tuted entities by their safe substitutes.
`
`3.1. Class-level Modification
`
`A class such as Window can be replaced with a subclass
`of Window (say Safe$Window) that restricts resource us-
`age and functionality. For example, Safe$Window’s con-
`structor can limit the number of windows that can be open
`at one time, by calling Window’s constructor, and raising
`an exception when the number of windows opened cur-
`rently (stored as a private variable in the method) exceeds
`the limit. Since Safe$Window is defined to be a subclass
`of Window, the applet should not notice the change, unless
`it attempts to create windows exceeding the limit.
`This class substitution is done by merely substitut-
`ing references to class Window with references to class
`Safe$Window. When Safe$Window is a subtype of
`Window, type Safe$Window can be used anywhere type
`Window is expected.
`In Java, all references to strings, classes, fields, and
`methods are through indices into the constant pool of the
`class file [16]. Therefore, it is the constant pool that should
`be modified in a Java class file. More specifically, two
`entries are used to represent a class in the constant pool.
`A constant pool entry tagged as CONSTANT Class repre-
`sents a class while referencing a CONSTANT Uft8 entry
`for a UTF-8 string representing a fully qualified name of
`the class, as in figure 1.
`If we replace a class name of a CONSTANT Uft8 en-
`try, Window, with a new class name, Safe$Window,
`the CONSTANT Class entry will represent the new class,
`Safe$Window, as shown in figure 2.
`Substituting a class requires just one modification of a
`constant pool entry representing a class name string. This
`is straightforward since a subclass may appear anywhere a
`superclass is used without any modifications to the program.
`However, this approach cannot be applied to a final class or
`an interface class.
`
`3.2. Method-level Modification
`
`In class-level modification, the basic idea is to substitute
`a potentially harmful method (for example, those that pro-
`vide direct access to system resources) with a safer version
`that provides for customized control. Unlike class-level
`modification, however, there is no relationship between the
`two methods. This provides more flexibility in that it can be
`used even when the method is final or is accessed through
`an interface, but requires more modifications than a simple
`substitution of methods.
`
`Juniper Ex. 1008-p. 3
`Juniper v Finjan
`
`
`
`class name index
`
`CONSTANT_Class entry
`
`class name
`
`CONSTANT_Utf8 entry
`
`CONSTANT POOL
`
`Figure 1. Class references in the constant pool
`
`11
`
`101
`
`11
`
`101
`
`101
`
`java/awt/Window
`
`101
`
`Safe$Window
`
`Before
`
`After
`
`Figure 2. Modfying class references
`
`Before getting into the general mechanism, let us con-
`sider a field and a method descriptor within the Java class
`file format. The field descriptor represents the type of a
`class or instance variable. For example, the descriptor of an
`int instance variable is simply I. Table 1 shows the mean-
`ing of some field descriptors.
`
`Descriptor
`C
`I
`Z
`L(cid:3)classname(cid:4);
`
`Type
`character
`integer
`boolean
`an instance of the class
`
`Table 1. The meaning of the field & method
`descriptors
`
`The Method descriptor represents the parameters that
`the method takes and the value that it returns. A parameter
`descriptor represents zero or more field types, and a return
`descriptor a field type or V. The character V indicates that
`the method returns no value(void). For example, the
`method descriptor for the method
`void setPriority (Thread t, int i)
`
`is
`
`(Ljava/lang/Thread;I)V
`
`We will describe an instance method in the form
`(cid:3)ClassName.MethodNameAndType(cid:4) and an class(static)
`method in the form (cid:3)ClassName:MethodNameAndType(cid:4),
`
`to distinguish them, though they are not distinguished in the
`constant pool.
`A method such as Thread.setPriority(I)V can
`be replaced with a safer version, say Safe$Thread:-
`setPriority(Ljava/lang/Thread;I)V, which
`does not allow threads spawned by mobile code to have
`higher priority than a user-specified upper limit defined
`in class Safe$Thread. The new safeguarding method
`takes priority of type integer as one of the arguments,
`and compares it with its upper limit.
`If the argument is
`higher, the argument is set to the upper limit. Eventually,
`the new method invokes Thread.setPriority(I)V
`with the verified argument. Since the new method invokes
`an instance method mentioned before, a reference to an
`instance of class Thread should be passed to the new
`method.
`
`3.2.1 Method Reference Modification
`
`It is more difficult to represent a method than a class;
`consequently the bytecode modification procedure for
`methods is more involved.
`A constant pool entry
`tagged as CONSTANT Methodref represents a method
`of a class(a static method) or of a class instance(an in-
`stance method).
`The CONSTANT Class entry repre-
`senting the class of which the method is a member
`and the CONSTANT NameAndType entry representing
`the name and descriptor of the method are referenced
`by CONSTANT Methodref.
`In our example, the CON-
`STANT Class entry and the CONSTANT NameAndType
`
`Juniper Ex. 1008-p. 4
`Juniper v Finjan
`
`
`
`entry reference the CONSTANT Uft8 entries represent-
`ing java/lang/Thread.setPriority and (I)V, re-
`spectively.
`Since a new class appears, we should add a new CON-
`STANT Uft8 entry representing a new classname string,
`Safe$Thread, and another new CONSTANT Class en-
`try referencing the new CONSTANT Uft8 entry, and
`then modify the CONSTANT Methodref entry to re-
`fer to the new CONSTANT Class entry instead of an
`old CONSTANT Class entry (which represents the class
`java/lang/Thread.)
`Since a method descriptor
`changes, we also need to add a CONSTANT Uft8 en-
`try representing a symbolic name for the new method de-
`scriptor, (Ljava/lang/Thread;I)V, and then mod-
`ify the CONSTANT NameAndType entry to refer to the
`new CONSTANT Uft8 entry for the method descrip-
`tor. Now the CONSTANT Methodref entry represents
`a new method, Safe$Thread:setPriority(Lja-
`va/lang/Thread;I)V, as shown in figure 3.
`
`3.2.2 Method Invocation Modification
`
`Among various Java Virtual Machine instructions im-
`plementing method invocations, we are interested in
`invokevirtual for an instance method invocation
`and invokestatic for a class(static) method invoca-
`tion.
`Both instructions require an index to a CON-
`STANT Methodref constant pool entry, but they require
`slightly different environments. The instance method in-
`vocation is set up by first pushing a reference, to the in-
`stance which the method belongs to, onto the operand
`stack.
`The method invocation’s arguments are then
`pushed onto the stack.
`The contents of the stack at
`this point (the environment), which include the refer-
`ence to the method and the operand stack of the call
`to Thread.setPriority(I)V, is shown in Figure
`4(a).
`The class method invocation requires an en-
`vironment much like that of the instance method in-
`vocation, except
`that a reference to the instance is
`not pushed onto the operand stack.
`The environ-
`ment of a call to Safe$Thread:setPriority(Lja-
`va/lang/Thread;I)V is shown in Figure 4(b).
`A visual comparison of the two method invocation envi-
`ronments in figure 4 makes the modification required very
`clear. The contents of the operand stacks are the same,
`though an instruction for method invocation changes from
`invokevirtual to invokestatic.
`The distinct nature of methods and classes, and their
`distinct representation in bytecode thus leads to different
`mechanisms for their respective modification. Method-level
`modification requires a change in bytecodes in addition to
`some modifications in the constant pool, whereas class-
`level modification requires only one change in the constant
`
`pool. The difference in the costs of these operations is made
`up by the difference in the applicability of the schemes;
`method-level modifications provide finer-grained control,
`and are the only choice for final classes and interfaces.
`
`4. Application Frameworks
`
`Our experiments with bytecode transfer and untrusted
`code execution were carried out in the context of Java ap-
`plets and Jini service proxies. While the same instrumen-
`tation mechanisms apply in both cases (and, in general, for
`arbitrary bytecode), the transport mechanism is modified at
`different points. In the following, we refer to the code which
`carries out the bytecode instrumentation as the bytecode fil-
`ter.
`
`4.1. Java Applets
`
`The ubiquity of Java applets and their usefulness comes
`at the price of an increased security risk owing to unin-
`tentional execution of malicious mobile code during web
`browsing.
`There are two obvious ways of inserting a Java bytecode
`filter into the network and browser architecture. One ap-
`proach would be to modify the class loader of the Java vir-
`tual machine used by the browser. The other is to capture
`and modify Java bytecode before it enters the browser. The
`latter provides an easier experimental framework, since a
`user can easily configure his or her browser to obtain web
`content through a piece of software called a network proxy.
`This can be done by a simple modification to a standard
`browser dialog box. In contrast, modifying the class loader
`of the Java virtual machine requires installation of special-
`purpose code in every browser. Moreover, using a standard
`proxy interface allows us to install a Java-based “security-
`tuner” interface in every browser, which allows the user to
`specify their security constraints. Thus a proxy interface
`provides a simple, customizable and flexible framework for
`developing and testing Java bytecode filters.
`The basic architecture of our system is shown in Fig-
`ure 5. When the web browser requests a web page or applet,
`this request goes through the network proxy. The proxy for-
`wards the request to the web server and receives the desired
`display or executable content. When the web server sends a
`Java applet, the proxy will pass the applet code to the byte-
`code filter. The bytecode filter will examine the bytecode
`for potential risks and modify the bytecode before sending
`the code for execution to the web browser. In this way, the
`web browser only receives bytecode that has been screened.
`The proxy also has access to a repository of Java classes, in-
`cluding secure safe classes that can be substituted for stan-
`dard library classes and implementations of user-interface
`methods. The user interface, written in Java and run as an
`
`Juniper Ex. 1008-p. 5
`Juniper v Finjan
`
`
`
`CONSTANT_Class
`
`entry
`
`CONSTANT_Methodref
`
`entry
`
`CONSTANT_NameAndType
`
`entry
`
`CONSTANT_Utf8
`
`entry
`
`CONSTANT_Utf8
`
`entry
`
`CONSTANT_Utf8
`
`entry
`
`CONSTANT_Class
`
`entry
`
`CONSTANT_Methodref
`
`entry
`
`CONSTANT_NameAndType
`
`entry
`
`CONSTANT_Utf8
`
`entry
`
`CONSTANT_Utf8
`
`entry
`
`CONSTANT_Utf8
`
`entry
`
`CONSTANT_Utf8
`entry
`CONSTANT_Class
`entry
`CONSTANT_Utf8
`entry
`
`- - - - - -
`
`- - - - - - - - -
`
`11
`21
`
`31
`
`101
`
`111
`
`121
`
`101
`
`11
`
`111
`
`31
`
`121
`
`java/lang/Thread
`
`setPriority
`
`(I)V
`
`(a) reference to
`
`Thread.setPriority(I)V
`
`11
`
`21
`
`31
`
`101
`
`111
`
`121
`
`201
`202
`203
`
`101
`
`202
`
`111
`
`31
`
`203
`
`java/lang/Thread
`
`setPriority
`
`(I)V
`
`Safe$Thread
`
`201
`
`(Ljava/lang/Thread;I)V
`
`(b) reference to
`
`Safe$Thread.setPriority(Ljava/lang/Thread;I)V
`
`Figure 3. Modifying method reference
`
`Juniper Ex. 1008-p. 6
`Juniper v Finjan
`
`
`
`top
`
`I
`Ljava/lang/Thread;
`
`push instance Ljava/lang/Thread;
`
`(instance)
`
`push argument I
`
`(argument)
`
`invokevirtual
`
`#21
`
` Operand Stack
`(a) Instance method invocation of Thread.setPriority(I)V
`
`top
`
`I
`Ljava/lang/Thread;
`
`push instance Ljava/lang/Thread;
`
`(argument)
`
`push argument I
`
`(argument)
`
`invokestatic
`
`#21
`
` Operand Stack
`(b) Class method invocation of
`
`Safe$Thread.setPriority(Ljava/lang/Thread;I)V
`
`Figure 4. Modifying environments of method invocations
`
`applet under control of the browser, allows the user to cus-
`tomize the security checks performed by the proxy and fil-
`ter during a web session, without stopping or restarting the
`browser or Java virtual machine running under control of
`the browser.
`
`4.2. Jini Proxies
`
`The Jini architecture and application program interfaces
`provide a convenient and relatively general framework for
`dynamic discovery and configuration of distributed ser-
`vices. Although Jini is designed to support dynamic federa-
`tion, the security aspects of Jini are extremely limited. The
`proliferation of networked small devices and the availabil-
`ity of lean JVMs makes Jini an obvious target for attacks in
`such a distributed system. We describe the basic Jini mech-
`anisms below, and demonstrate the use of our techniques to
`ensure safety in this framework.
`
`4.2.1 Protocols
`
`The Jini API extends the Java environment from a single
`virtual machine to a network of machines.
`In general, a
`Jini system contains a set of services each of which offers
`some functionality to any member of a federation. The ini-
`tial handshake between the clients and the services is facil-
`itated by lookup services. The location and installation of
`services via this lookup mechanism involves network trans-
`fer of Java bytecode. Specifically, if a process on machine A
`
`wishes to communicate with a process on machine B, then
`machine A installs a surrogate stub object that communi-
`cates with a corresponding object on machine B through re-
`mote method invocation. This surrogate stub object is called
`a proxy. If the object on machine B provides a lookup ser-
`vice, then the stub object installed on machine A is called a
`lookup proxy. If the object on machine B provides a general
`distributed service, then the stub object installed on machine
`A is called a service proxy.
`A Jini client obtains a lookup proxy and a service proxy
`through the following steps:
`
`Discovery The client broadcasts a request for a lookup
`service. The lookup service responds with a lookup
`proxy. This stub object (proxy) allows the client to
`make further queries of the lookup service.
`
`Query The client queries the lookup service for a service
`with specific attributes. The lookup service responds
`with a list of services and supplies a list of attributes
`associated with each service. v
`
`Selection The client requests and receives a service proxy
`for a specific service. The result of selection may be a
`signed or unsigned jar (java archive) file.
`
`The first phase, used in discovery, involves communication
`with a subnet or multicast group, in order to locate a lookup
`service.
`In the second phase, which includes query and
`selection, the agent communicates with the lookup service
`through a lookup proxy that was obtained in the discovery
`
`Juniper Ex. 1008-p. 7
`Juniper v Finjan
`
`
`
`Internet
`Web
`Server
`
`Internet
`
`Modified
`Applet
`
`Proxy
`
`Bytecode
`Filter
`
`Safe
`Classes
`
`Figure 5. Architecture for instrumenting Java applets
`
`Lookup Service
`
`L S
`
`DISCOVER
`
`QUERY
`
`JOIN
`
`Client
`
`Class
`Loader
`
`S
`
`Service
`
`Lookup
`Proxy
`L
`
`Service
`Proxy
`S
`
`ACCESS
`
`FILTER
`Safe Class Library
`
`Figure 6. Architecture for instrumenting Jini proxies
`
`Juniper Ex. 1008-p. 8
`Juniper v Finjan
`
`
`
`phase. While standard Jini uses remote method invocation,
`other forms of communication could conceivably be sub-
`stituted. Since the agent must install and execute a lookup
`proxy (interface or driver), the agent is susceptible to errors
`or attacks resulting from corrupted or malicious proxy code.
`In the third phase, the agent interfaces with the installed ser-
`vice through a service proxy. Again, standard Jini relies on
`remote method invocation, but if the service is distributed,
`then other communication mechanisms could be appropri-
`ate. As with installation of the lookup proxy, the agent is
`again subject to risks associated with execution of service
`proxy code received over the network.
`
`4.2.2 Security
`
`The current Jini security model is simply the Java secu-
`rity model. The final jar file received as the result of se-
`lection may be signed. The client Java security manager
`may be configured to provide each lookup proxy or service
`proxy with specific access rights, according to the signing
`key used in creation of the jar file. This provides some
`protection, but suffers from the familiar shortcomings of
`signature-based security. Specifically, authenticated code
`may have unintentional safety loopholes, which are only
`adequately addressed by a content-based protection mecha-
`nism. Instrumenting the proxy bytecode at the client’s end,
`before it is loaded by the class loader for execution, pro-
`vides for client-specified safe behavior.
`Figure 6 illustrates the augmented Jini architecture. Note
`that specific kinds of bytecode filtering may be appropriate
`for Jini. For example, if Jini service proxies (consisting of
`java bytecode) are not expected to contain loops, then filter-
`ing can be used to detect this and prevent looping. Another
`desirable property might be that the proxy only engages in
`secure authenticated network connections with the service
`it came from, and the code may be filtered to require this.
`Other client and service specific tests may be performed by
`instrumenting the proxy with sentinel code, which performs
`the required code analysis prior to execution of the original
`code. Jini-specific filtering can be achieved either by writ-
`ing appropriate configuration files for our existing filter, or
`extending the filter implementation.
`The second piece of the augmented Jini infrastructure
`is an interception mechanism for proxy bytecode. As de-
`scribed above, for Java applets this was achieved by using
`a network proxy that intercepted http communication. For
`Jini, this must now be done using a network proxy or some
`other mechanism that has access to arguments and return
`values of Java RMI calls.
`
`4.2.3 Bytecode Interception
`
`The Jini specification only requires the protocols described
`above to be based on TCP and UDP transport and ob-
`
`ject serialization, and implementations are free to choose
`a communication mechanism. In particular, the specifica-
`tion makes no particular reference to the RMI registry or
`wire protocols. The only requirement is that Jini inter-
`faces preserve the RMI remote interface semantics, which
`means that they need to only declare RemoteException
`on its methods. This makes the job of identifying a well-
`known, constant path of remote-class delivery rather diffi-
`cult. We note though that most Jini communities of services
`and clients actually use RMI, on account of it being used in
`Sun’s default implementation.
`We focus on the relevant parts of the Jini discov-
`ery protocol. After the lookup server is found, it sends
`to the client an object implementing the net.jini.-
`core.lookup.ServiceRegistrar interface. This
`is done in the last phase of the discovery protocol,
`via a java.rmi.MarshalledObject. This Ser-
`viceRegistrar object is the lookup proxy, and will re-
`ceive all service proxies on the clients behalf. Accordingly,
`there are three places where one could intercept the service
`proxy bytecode:
`
`(cid:2) during transport from the lookup server to the lookup
`service proxy,
`
`(cid:2) within the ServiceRegistrar before the serial-
`ized object is reconstructed, and
`
`(cid:2) within the ServiceRegistrar after object recon-
`struction.
`
`The lack of a common wire protocol makes it infeasible
`to intercept the service object along the network path, thus
`we intercept the object bytecode in the ServiceRegis-
`trar. This is best done before the serialized object is re-
`constructed, since modifying the bytecode of an object after
`reconstruction presents problems. For example, it is diffi-
`cult to maintain the state of the object.
`In Java, in order to load a class into the JVM exe-
`cution, one needs a java.lang.ClassLoader object
`which does the actual loading via the protected final de-
`fineClass method. Loading a class in the JVM proceeds
`as follows. If the class name is referenced implicitly during
`the code execution, the JVM tries to locate in its internal
`runtime table a class with such name, that was loaded by the
`same ClassLoader which loaded the class making the refer-
`ence. If there is no such class, the JVM calls the method
`loadClass() on the ClassLoader which loaded the
`class making the reference. This method first tries to del-
`egate the loading of the class to its parent ClassLoader
`by calling its loadClass(), and so forth, up until the
`bootstrap. If all parents fail to locate the class (not previ-
`ously loaded by them, and unable to find its .class file), then
`loadClass() calls findClass() in the ClassLoader
`that initiated the loading process. If findClass finds the
`
`Juniper Ex. 1008-p. 9
`Juniper v Finjan
`
`
`
`.class file, it loads it into a byte array, and then c