University of Virginia, Department of Computer Science
CS551: Security and Privacy on the Internet, Fall 2000

Problem Set 4: Systems Security Selected Answers

Average: 87.5/100
Problem 1: 42.7/50
Problem 2: 30.4/35
Problem 3: 14.4/15

1. Security Design Principles (50 points)

Here is William GJ Halfond and Jorge Estrada Collado's answer for Going Beyond the Sandbox : An Overview of the New Security Architecture in the Java Development Kit 1.2.

a) Economy of Mechanism

After reading through the numerous methods and mechanisms that make up Java security we concluded that Java fails to conform to the principle of economy of mechanism both in its model and its implementation. Several things contribute to this. One is that Java 1.2 tries to maintain backwards compatibility with older security models. This in itself causes the implementation of the new security models to become overly complicated and prone to error. While it is obvious that this is a necessary compromise in order to facilitate the acceptance of Java 1.2 into the marketplace, it still causes the implementation to be more complicated than is desirable. The new Java security model has been described as instead of implementing a black and white model, it now implements shades of gray. In our analysis we found not only this "horizontal" shading, but a vertical tier of increasing granularity that made it possible to restrict/deny permission to files and resources down to the atomic level. This high level of control and granularity adds immense complexity to the logical security model. On top of this there are over 700 rules in the JVML (according to lecture slides) that further complicate the enforcement and understanding of the Java security model. Certainly, much of this added complexity was a concession to enterprise developers and administers who needed to administer and implement security mechanism on a much more fine grained level than earlier versions of Java allowed. It's for this reason we surmised, that the Java developers allowed the complexity to enter their security model. While it is clear to see that the granularity and control create a more complicated security model, we were not sure what type of effect this had on the complexity of the implementation. Since Java is a strongly object oriented language we could imagine how object orientation could be used to reduce the complexity associated with this security model.

b) Fail-safe Defaults

Java implements fail-safe defaults. In specific we found three important examples of where this was used to increase security. The first was in the behavior of the Access Controller class. This is the mechanism that checks to see if calling functions have permissions or privileges that they are trying to use. This is especially important in situations where there are several applications or functions on the call stack. It is necessary to determine if all of them are able to access the requested privilege. The default behavior for the Access Controller is to allow access only in the case that all callers in the thread history belong to a domain that have granted that privilege. This is often times a very limiting and annoying feature, but it enforces a minimum fail safe in all situations unless it is specifically overridden. The second example was in the usage of the security policies. By default the security policy for any applet or application is to deny access to network, file and most other system services. These privileges must be specifically enabled by the user or security administrator in order for the Java application to be able to use them. Together these two mechanisms compromise the bulk of the Java security model and therefore since they implement fail-safe defaults we feel it is safe to say that Java on the whole implements fail-safe defaults. The third example of an intended fail-safe default is the fact that the class loader only accepts files in the CLASSPATH as system files. However, while this seems like a reasonable and useful fail-safe default to have, we do not believe that it holds up in normal usage. It is too easy to accidentally circumvent this fail safe default. For example, many programmers commonly store their code in the CLASSPATH and mistakenly installing insecure code in the CLASSPATH could open a door to allowing a malicious class run of the system.

c) Complete Mediation

Java's implementation of complete mediation is almost achieved. According to the specs of the model, every call or access to a system's resource is mediated by the Security Manager class. This ensures that no access to system resources can happen without it first being checked to see if the caller has the necessary privileges. In theory Java does not use a system of remembering authority checks and using past results to rule on new requests, which makes its complete mediation more secure. (We say in theory because implementations might not behave as they should) Saltzer and Schroeder mention that a foolproof method for identifying the sources of every request must be in place to have complete mediation. In this respect, Java is not perfect. This area has been mentioned by Sun developers as a direction for future Java work. In the meanwhile, Java has set up fail-safe defaults that force programmers to make decisions about who may access system resources. (Re: Access Control class)

d) Open Design

Sun has made freely available the specifications and design of its Java virtual machine. This has allowed the security community to evaluate the theoretical design and assumptions made in designing the Java security model. In addition Sun (according to an article on the Sun site) has made the source code to its Java virtual machine freely available. This is crucial to fulfilling Saltzer and Schroeder's principle of open design. By additionally having the mechanism of implementation available, the security community is also able to check over and verify the implementation of the security model. This is necessary to both convince users that no potential holes exist and to facilitate further development on the robustness of the model. Furthermore, by also opening the source, it leaves behind the notion that security by obscurity is an effective way to prevent breaches from occurring in the virtual machine.

e) Separation of privilege In our review of the paper we were not able to find good examples of separation of privilege. By this we mean that we couldn't find examples that used two unlocking mechanism or shared the responsibility of restricting access. But we did find one example of a mechanism that in a very loose way resembles separation of privilege. This had to do with the Java virtual machine's interaction with the underlying OS. Sun states that their "architecture does not override the protection mechanisms in the underlying operating system." This would mean that even if the JVM grants a user fine grained permission to access a file, if the underlying system does not allow this access to take place, the operation as a whole will fail. In terms of separation of privilege, this mechanism means that two security checks are necessary to access a privilege. Of course, if the JVM runs under the permissions of the administrator or root, this becomes irrelevant.

f) Least Privilege

Java attempts to implement the design principle of least privilege by intersecting permissions granted to different domains that are part of a call sequence. It then uses the resultant set to restrict the behavior of the called resource. Java's ability to use fine granularity when determining permissions can be seen as an enhancement to this. It means that the resultant set will be smaller and more restricted than if more general policy permissions were intersected. There are two shortcomings in Java's model for implementing least privileges. First is that Java provides a method for overriding permissions allowed in a call sequence. A class may do this by the begin and end privileged methods. This enables it to call functions and access resources that it might not otherwise be allowed to do if the caller did not have sufficient permissions. This leaves a glaring hole in the implementation of the least privileges design. However, the practicality of having such an ability is fairly obvious. There are often situations in which a system class must access resources that would otherwise be unavailable to the caller. The second problem is found in the practice of signing code. In practical application a programmer can sign a piece of code with multiple keys while failing to realize that the union of the privileges of the two keys will then be the privileges for the program. This could inadvertently allow a program to have a much wider range of permission than was originally intended.

g) Least Common Mechanism

Java has two methods of implementing the least common mechanism principle. The class loader creates a local name space that is used to prevent programs from accessing and intruding in on other application's data and variables. Also Java restricts the ability of programs operating in different security domains from communicating with each other. This restriction in itself helps to reduce the chance that applications running in less permissive domains can interact with more privileged applications running in a separate domain. Saltzer and Schroeder identify the ability to implement functions and new procedures as libraries instead of supervisor procedures. This allows the user to choose whether to use the library or override it with one of their own if they choose. In this regard, Java allows the user to choose which libraries and objects will be imported into an application. It also allows users to override a fair amount of library functions if they are unhappy with their method of execution. However, one shortcoming in the least common mechanism implementation that we found was the reliance on a system wide garbage collector. We saw this as opening the door to a possibility that a bug in this system could be used or leveraged by other programs to cause security breaches in an application. On the flip side of this issue, we can see that the decision to include the garbage collector was a practical tradeoff. It is far more likely that programmers will have memory leaks and other memory management issues than that there will be serious problems in the garbage collector.

h) Psychological acceptability

While subsequent versions of Java have made significant improvements in making security easier to use and integrate by programmers, it still fails to achieve the level of integration that we would like to see. Because of the complexity of the security model we see enormous potential for minor oversights to become security breaches. With the combination of broad policies and fine-grained control, it becomes too easy to inadvertently grant permissions that should have remained restricted. Also, with such fine grained control available via the Access Control class and conversely broad control offered by policies, it is inevitable that rushed or lazy programmers will by default grant a larger domain of privileges than is necessary in order to make usage and programming easier. Other security mechanisms are based on programmers remembering the significance of their action, such as signing code with multiple keys (see previous response) and forgetting to end the begin privileged blocks of code. These are easy slips to make which could potentially open up security holes in software.

2. Risks (35)

Everyone wrote about different things. Some of the answers were quite good, but none I considered good enough to be worth handing out.

3. Naming (15)

See lecture slides.

[an error occurred while processing this directive]