Due: Wednesday, February 12 by the end of the day. This means that your submission must be dated on or before that date, so you have until midnight.
Remember that you can work on this assignment with one other student. Please indicate clearly in your README file who you (both) are.
Each assignment is graded on a 10 point scale. For this assignment, it is possible to get up to 2 extra credit points. That information is at the bottom.
Deliverables: You will be submitting your code electronically using Canvas. Your program must be able to run on the UT Linux machines, so if you develop it on Windows, make sure it runs on Linux.
Please zip your Java implementation files and README.txt file together and submit a single zip file for the main program, and a separate zip file if you also do the extra credit. You should include either or both of the extra credit steps in one file. Don't forget to name your zip files according to the instructions.
Your zip file should contain a README.txt file containing:
Your assignment is to implement in Java a simple "secure" system following the Bell and LaPadula (BLP) security rules--simple security, the *-property, and strong tranquility. Take care with this assignment, because it will form the basis of the next assignment as well. Imagine a system with subjects and objects. Objects in this system are simple integer variables. Each object has a name and a value (initially 0). Each subject has a name and an integer variable TEMP recording the value it most recently read (also initially 0). Subjects can perform READ or WRITE operations on objects. For a READ, the subject reads the current value of the object, and saves that value into its TEMP variable (a subsequent READ will smash it). When a subject does a WRITE, the object's value is updated. Objects are managed by the ObjectManager class. Think of ObjectManager as a very simple file system that READs and WRITEs objects by name.
The input to your system is a file of commands. For the current assignment, the only legal commands are of the form:
READ subject_name object_name WRITE subject_name object_name value
All fields of the instruction are strings except the value, which is an integer.
You will read successive lines from the file and parse each into an InstructionObject class object. Commands are not case-sensitive, even object and subject names. Arbitrary whitespace is allowed in commands, but assume that each command is on one line.
Be sure to deal with the possibility of errors in the instructions (neither READ nor WRITE, wrong number/type of arguments, unknown subject/object, etc.). For illegal instructions, generate a BadInstruction constant object.
Suppose hal and lyle are the only Subjects known in your system and lobj and hobj are the only Objects known in the system. Now, suppose your input file contains the following list of instructions. The top three and the last three are bad and the others syntactically OK (though they may not be permitted by the security policy).
write hal hobj read hal read sal sobj write lyle lobj 10 read hal lobj write lyle hobj 20 write hal lobj 200 read hal hobj read lyle lobj read lyle hobj foo lyle lobj Hi lyle, This is hal The missile launch code is 1234567We might write an interpreter for this system, that would perform the legal instructions and ignore the others. A reasonable implementation might end with a state in which the objects have values: lobj 200 and hobj 20; the subjects' TEMP variables at the end would contain: hal 20 and lyle 20.
But now, let's add BLP security to our system. Start by giving both subjects and objects associated security labels (levels). These labels are maintained by a ReferenceMonitor class object and can't be changed after they are created (strong tranquility). Essentially, the reference monitor manages two mappings from subject/object names to security labels.
In the secure version of our system, whenever a subject requests to perform an action (READ or WRITE), the parsed InstructionObject is submitted to the reference monitor, which decides whether to perform the action or not based on the BLP properties (Simple Security and the *-Property). If the instruction is both syntactically legal and is allowed by the BLP rules, the reference monitor tells the ObjectManager to perform the appropriate action; otherwise, no objects are accessed.
Assuming an instruction is not Bad, the reference monitor always returns an integer value to the subject: the value of the object read, if the command was a legal READ; and 0 otherwise. If the subject is performing a READ, it stores this value into its TEMP variable. Think of the reference monitor as a firewall around the ObjectManager. Note that the ObjectManager itself doesn't know or care about labels or security; it just performs simple accesses.
The top-level class (SecureSystem) manages subjects and the reference monitor, and also serves as the command interpreter. It reads successive instructions from the instruction list, parses them, and submits them to the reference monitor, which asks the ObjectManager to perform them (or not). The value returned by the reference monitor is passed to the subject executing the instruction.
Your task is to implement all this, subject to the following constraints.
However, for the production run (the one we'll grade) your output must be more constrained. We'll say more below.
The main function in your SecureSystem class should perform the following tasks:
You should following good programming practices, making your code modular and using good abstractions. For example, SecurityLevel should be a class that defines levels and Dominates in such a way that you might later add need-to-know categories without changing much outside the class. Don't take a bunch of shortcuts that result in lousy code.
Below is a snippet of code from my main function. You don't have to follow this model, but you're welcome to.
// LOW and HIGH are constants defined in the SecurityLevel // class, such that HIGH dominates LOW. SecurityLevel low = SecurityLevel.LOW; SecurityLevel high = SecurityLevel.HIGH; // We add two subjects, one high and one low. sys.createSubject("lyle", low); sys.createSubject("hal", high); // We add two objects, one high and one low. sys.getReferenceMonitor().createNewObject("Lobj", low); sys.getReferenceMonitor().createNewObject("Hobj", high); ...
While designing your system consider the following questions: Are there security flaws in this design? What are they? How might you go about fixing them?
Consider the list of instructions given above. Below is a description that shows what is happening as each line is executed. This is not what your output should look like, but you should make sure you understand how each instruction updates the state. The actual output is lower on this page.
The initial state is: lobj: 0 hobj: 0 lyle: 0 hal: 0 Instruction: "write hal hobj" Bad Instruction The current state is: lobj: 0 hobj: 0 lyle: 0 hal: 0 Instruction: "read hal" Bad Instruction The current state is: lobj: 0 hobj: 0 lyle: 0 hal: 0 Instruction: "read sal sobj" Bad Instruction The current state is: lobj: 0 hobj: 0 lyle: 0 hal: 0 Instruction: "read hal" Bad Instruction The current state is: lobj: 0 hobj: 0 lyle: 0 hal: 0 Instruction: "write lyle lobj 10" OK to execute The current state is: lobj: 10 hobj: 0 lyle: 0 hal: 0 Instruction: "read hal lobj" OK to execute The current state is: lobj: 10 hobj: 0 lyle: 0 hal: 10 Instruction: "write lyle hobj 20" OK to execute The current state is: lobj: 10 hobj: 20 lyle: 0 hal: 10 Instruction: "write hal lobj 200" Fails BLP tests The current state is: lobj: 10 hobj: 20 lyle: 0 hal: 10 Instruction: "read hal hobj" OK to execute The current state is: lobj: 10 hobj: 20 lyle: 0 hal: 20 Instruction: "read lyle lobj" OK to execute The current state is: lobj: 10 hobj: 20 lyle: 10 hal: 20 Instruction: "read lyle hobj" Fails BLP tests The current state is: lobj: 10 hobj: 20 lyle: 0 hal: 20 Instruction: "foo lyle lobj" Bad Instruction The current state is: lobj: 10 hobj: 20 lyle: 0 hal: 20 Instruction: "Hi lyle, This is hal" Bad Instruction The current state is: lobj: 10 hobj: 20 lyle: 0 hal: 20 Instruction: "The missile launch code is 1234567" Bad Instruction The current state is: lobj: 10 hobj: 20 lyle: 0 hal: 20But what your program will generate in production mode is the following output:
> java SecureSystem instructionList bad 0 0 0 0 bad 0 0 0 0 bad 0 0 0 0 write 10 0 0 0 read 10 0 0 10 write 10 20 0 10 write 10 20 0 10 read 10 20 0 20 read 10 20 10 20 read 10 20 0 20 bad 10 20 0 20 bad 10 20 0 20 bad 10 20 0 20For each line, there should be five fields separated by a single space. The first field should contain one of the lower case keywords: "bad", "read", "write." Use "bad" only if the instruction is syntactically illegal; not if it's not permitted by BLP. The other four fields contain the values in order of lobj, hobj, value most recently read by lyle, value most recently read by hal. If the instruction is not permitted by BLP, you should still indicate the attempted operation. Even for a failed instruction, the values may still change; for example, a failed READ returns a 0 to the reading subject. The TA should be able to pipe your output to a file and compare the file to his test. They should be identical!
You can get up to 2 points extra credit on this assignment: 1 point for the threaded implementation and 1 point for adding a SLEEP instruction. You can only do the SLEEP part, if you are also doing the threaded implementation.
Since it's extra credit, I'm not going to give you detailed instructions on this part. If you want to do this one, you will have to use some ingenuity, though I'm happy to help you individually.
The assignment above is unrealistic in that the actions of subjects lyle and hal are totally synchronized according to the ordering of instructions in the input. Reimplement this assignment so that lyle and hal run as separate processes (threads), each reads from its own instruction file (remove the subject name argument to each instruction), and the reference monitor is a shared resource.
If you do this in the most straightforward way, they will run in an arbitrarily interleaved fashion depending on the OS scheduling. If the instruction lists are fairly short, whichever one gets the processor first likely will just blow through his instruction list, finishing before the other thread ever runs. Add an additional SLEEP instruction that relinguishes the processor. I.e., if hal is running and executes a SLEEP instruction, then the processor should be handed to lyle, etc. That way you can force interesting interleavings. Note that this still may not work as expected on multi-processor systems where the threads are scheduled on separate processors. You may be able to deal with this issue by SLEEPING for some microseconds. Printing of the output may be oddly interleaved. Don't worry about that.
If you're having problems with the threads programming, these may help. Here is an excellent description of Java Synchronization by Ron Rockhold: Java Synchronization, and a link to a helpful short paper by Prof. Mike Dahlin: Threads Programming.