SECURITY SANDBOXING FOR PC2 Vikram Chidanand Adithya B.E., Visvesvaraya Technological University, India, 2006 PROJECT Submitted in partial satisfaction of the requirements for the degree of MASTER OF SCIENCE in COMPUTER SCIENCE at CALIFORNIA STATE UNIVERSITY, SACRAMENTO FALL 2011 SECURITY SANDBOXING FOR PC2 A Project by Vikram Chidanand Adithya Approved by: __________________________________, Committee Chair John Clevenger, Ph.D. __________________________________, Second Reader V. Scott Gordon, Ph.D. ____________________________ Date ii Student: Vikram Chidanand Adithya I certify that this student has met the requirements for format contained in the University format manual, and that this project is suitable for shelving in the Library and credit is to be awarded for the Project. __________________________, Graduate Coordinator Nikrouz Faroughi, Ph.D. Department of Computer Science iii ________________ Date Abstract of SECURITY SANDBOXING FOR PC2 by Vikram Chidanand Adithya This project involves developing a Security Sandbox, which is a computer security tool that prohibits an application from making unauthorized system calls. This tool is used in PC2 which is Programming Contest Control System, pronounced “P-C-squared” or sometimes just “P-C-Two” for short. The Security Sandbox limits user submitted programs from accessing restricted system resources in a programming contest. Every semester, the Association of Computing Machinery (ACM) at California State University, Sacramento (CSUS) conducts a Programming Contest, which allows students from all majors to participate. Every participating student or a team of students have to solve certain questions and come up with a C, C++ or Java program as a solution for each problem. The judges verify the solution, give points accordingly, and choose the winner at the end of contest. iv PC2 is a software system developed at CSUS. It is used to support smooth flow of programming contests. Every participating team submits their programs to judges. PC2 takes submitted programs and runs them as a separate thread, reporting the execution results to the judges. This project provides a Security Sandbox that can hold and run the team submitted code. The judges give information regarding all system calls that are permitted for each problem of the contest. If the participant’s code tries to access unauthorized resources then the Sandbox will stop the code from execution and further reports it to the judges. The result of this project is a Linux based working prototype, a report on migrating it to other platforms such as Windows and Mac OS and finally deploy the Sandbox for Programming Contests. _______________________, Committee Chair John Clevenger, Ph.D. _______________________ Date v DEDICATION Dedicated to my loving parents, Chidanand Murthy & Usha Devi vi ACKNOWLEDGEMENTS I would like to take this excellent opportunity to thank Dr. Cui Zhang, Department Chair, Department of Computer Science, for her support and guidance throughout my MS program. I would also like to thank Dr. Nikrouz Faroughi, Graduate Coordinator, Department of Computer Science for his timely advice and support. I thank Dr. John Clevenger for offering me this project and advising me at every level, towards its completion. He provided new ideas and helped me in planning and executing the entire project. His Operating System Pragmatics course inspired me to take up this project. I take this opportunity to thank Dr. Scott Gordon for his willingness to become my second reader and in conducting the ACM coding contests, which sharpens the student’s skills and ability to think out of the box. I also thank the entire PC2 team who helped me in understanding PC2, resolving implementation issues, and in giving valuable suggestions. I take this opportunity to thank my loving parents Chidanand Murthy and Usha Devi who had the dream of making their son an engineer and wished him to become a MS graduate. I thank Eric Merchant and Tracey Culbertson from Office of Global Education for assisting me whenever I was in need of advice, from day one of my Master’s program until graduation and beyond. To all my friends who came across my life, supported me, motivated me and helped in being a successful person. To my hometown Tumkur, to her beautiful state of Karnataka and to her people. vii TABLE OF CONTENTS Page Dedication ....................................................................................................................................... vi Acknowledgements ........................................................................................................................ vii List of Figures ................................................................................................................................. xi Chapter 1. INTRODUCTION ....................................................................................................................... 1 1.1 Purpose of the Project ................................................................................................... 1 1.2 About PC2 ..................................................................................................................... 1 1.3 Problem Description ..................................................................................................... 2 1.4 Proposed solution.......................................................................................................... 3 2. EXISTING COMPUTER SECURITY TOOLS .......................................................................... 5 2.1 Ptrace ............................................................................................................................ 5 2.2 Systrace ......................................................................................................................... 6 2.3 Strace ............................................................................................................................ 6 2.4 Ktrace............................................................................................................................ 7 2.5 Conclusion .................................................................................................................... 7 3. WORKING WITH SECURITY TOOLS .................................................................................... 9 3.1 Ptrace ............................................................................................................................ 9 3.2 Systrace ....................................................................................................................... 12 4. SECURITY APPROACH FOR PROGRAMMING LANGUAGES ........................................ 15 4.1 With C/C++ ................................................................................................................ 15 4.2 With Java .................................................................................................................... 16 4.2.1 Using C/C++ with JNI....................................................................................... 16 viii 4.2.2 Using Java Security Manager ............................................................................ 18 5. SOFTWARE DESIGN AND APPROACH .............................................................................. 22 5.1 Design Flow ................................................................................................................ 22 5.1.1 Judge or Administrator ...................................................................................... 23 5.1.2 Problem # .......................................................................................................... 23 5.1.3 Problem Specific Judge Policy .......................................................................... 23 5.1.4 Base Policy ........................................................................................................ 23 5.1.5 The Generate Module ........................................................................................ 23 5.1.6 Problem Specific Executable File ..................................................................... 24 5.1.7 Problem Specific C/C++ Policy File ................................................................. 24 5.1.8 Problem Specific Output Log File Name .......................................................... 24 5.1.9 Indicator for C/C++ and Java ............................................................................ 24 5.1.10 The Execute Module ....................................................................................... 24 5.1.11 Security Violation............................................................................................ 24 5.1.12 Print: No Security Violation ............................................................................ 25 5.1.13 Print: Security Violation with reason .............................................................. 25 5.1.14 Output Log file ................................................................................................ 25 5.1.15 PC2 ................................................................................................................... 25 5.2 The Generate Module ................................................................................................. 25 5.3 The Execute Module ................................................................................................... 26 6. EXAMPLES OF SECURITY VIOLATION ATTEMPTS ....................................................... 31 6.1 Execution of system calls by Java using exec method ............................................... 31 6.2 Execution of System calls by Java using JNI ............................................................. 32 6.3 Java socket connection................................................................................................ 34 ix 6.4 C/C++ socket connection ............................................................................................ 36 6.5 Forking child process in C/C++ .................................................................................. 39 6.6 Assumptions and Limitations ..................................................................................... 40 7. DEPLOYMENT AND TESTING OF THE SANDBOX IN PC2 .............................................. 43 7.1 Executing team runs with no Sandbox ....................................................................... 43 7.2 Setting Up Sandbox Environment and Executing with Sandbox ............................... 44 7.2.1 Generating a C/C++ Base Policy File for Systrace ........................................... 44 7.2.2 Modifying Judge Policy File ............................................................................. 45 7.2.3 Generating C/C++ and Java policy files............................................................ 50 7.2.4 Modifying PC2 ................................................................................................... 52 7.3 Executing Team Runs With Sandbox ......................................................................... 52 8. CONCLUSION .......................................................................................................................... 54 8.1 Migration to other major Operating Systems.............................................................. 54 8.1.1 Mac OS .............................................................................................................. 55 8.1.2 Solaris ................................................................................................................ 55 8.1.3 Windows............................................................................................................ 55 8.2 Future Development ................................................................................................... 56 References ...................................................................................................................................... 58 x LIST OF FIGURES Figure 1 Complete Flow ................................................................................................................ 22 Figure 2 C/C++ Execution Flow.................................................................................................... 28 Figure 3 Java Execution Flow ....................................................................................................... 29 xi 1 Chapter 1 INTRODUCTION Computer security is one of the major factors that contribute to the successful execution of any software application. These software applications have to be completely secured; otherwise, they will be more vulnerable to attacks and can invite hackers. Providing security is based on factors such as the importance of the application to be secured, how distributed it is, intensity of potential loses and consequences if the application is hacked, cost for the security and several others. 1.1 Purpose of the Project This project aims at providing system level security in the form of a Security Sandbox, to an application called PC2, which is used for conducting programming contests. The participants of the contest submit their code to the judges through PC2. The Security Sandbox monitors the execution of submitted programs and checks if there are any unauthorized accesses to system resources or presence of any malicious content in the code, during execution. At the end, the Security Sandbox generates a log file, which states if there was any security violation or not. If the execution was successful and the code had no malicious content then the generated file contains “No Security Violation” string. Integration of the Security Sandbox into PC2 enhances the security features during programming contests. 1.2 About PC2 PC2 is an acronym for Programming Contest Control software system. This application was developed at California State University at Sacramento by the PC2 team. This system software supports programming contests conducted throughout the world, including the ACM (Association 2 of Computing Machinery) International Collegiate Programming Contest (ICPC) along with its Regional contests in six continents [1]. PC2 is designed to work in a variety of computing environments. The contest participants have to submit their code to the judges over a network. The judges preprogram PC2 to accept the participants code, compile it and execute. The result of the execution will be compared with the judge’s own output copy and the response will be sent back to the participants. PC2 has an option of making the entire receive-compile-execute-feedback process automated, which is called “automated judging”. This system also displays the current status of a participant which includes number of programs submitted, penalties encountered for wrong submission, current total points and where the participant stands in the contest. The contest administrator can tailor this system depending on specific contest operations like the number of teams, different set of problems ranging from lowest to the highest in difficulty levels, languages used in the contest, scoring methods and other important aspects. The system is designed to compile and run programs written in different languages. Therefore, the participants write their code in C/C++, Java, Perl etc., and can submit it to the judges. 1.3 Problem Description In a programming contest, the participants can submit their code to the judges who simply compile and run the code with required input data file. The result of this process gets saved in an output file, which is compared with the judge’s output file. If there are any differences then an appropriate message is sent to the participants. 3 If the participant has a bad intention, then he can write a malicious code that can harm the entire system and pose a threat to the integrity of the programming contest. For example, the participant may try to: 1. Establish a socket connection. 2. Delete some important files in the system. 3. Alter the scoring system. 4. Block submissions of other participants. Therefore, PC2 system is vulnerable to malicious code submitted by the participants. These have to be taken care for conducting a successful programming contest and to prohibit participants from taking actions based on their bad intentions of hacking [2]. 1.4 Proposed solution System calls in programming languages like file read/write operations and socket connections, have to go through kernel of the underlying operating system. If a program wants to execute some system command, it has to get itself trapped first by invoking a kernel service routine of the operating system. Once trapped, the kernel of the operating system checks the trap number and then executes the request. Therefore, monitoring of system calls is important in order to enforce limitations on the participant submitted program’s access. The program or application must have limited types of system calls to achieve a secured environment. An application can intelligently make system calls to change or access certain information from the system. There should be a monitoring tool to prevent applications from making unwanted and prohibited system calls. The role of this project comes in the form of monitoring the system calls made by the team submitted programs by implementing a system that provides a Security Sandbox, which can hold and run the participants’ code. The judges would have already given information regarding all the 4 system calls which are permitted for that particular contest and for that particular problem. If the participant’s code violates the protocol and tries to access unauthorized resources then the Sandbox would stop the code from execution and further report it to the judges. The Security Sandbox would be deployed only on the Judge or Administrator’s machine. Hence, the participants can run their code on their own machine with no Sandbox. Even if the participants succeed to execute any malicious code on their computer and submit it to the judges, the Sandbox on the Judge’s machine would stop the code from doing any such malicious activities that violates the protocol. Since the Security Sandbox will be deployed only on Judge or Administrator’s machine, a participant can attempt to run any malicious code and might succeed. The test run performed by the participant may try to change the submission time stamp of his or her code, may submit as a different participant, or perform any malicious activity that might disobey the rules of the contest. However, the Security Sandbox will not monitor these malicious activities at the participant’s side. It only sandboxes the code at the Judge’s side. Hence, if required, a different approach needs to be taken to monitor the test runs at the participant’s side. 5 Chapter 2 EXISTING COMPUTER SECURITY TOOLS Security Sandboxing isolates the participant submitted code by enclosing it inside a box, which has rules and policies. These policies force the code to adhere to the rules defined by the contest administrator. There are several ideas that can come up to one’s mind in order to implement the Sandbox. Before that, it is important to understand existing security tools that exhibit familiar behavior of a Sandbox. Some of the existing tools are discussed in this chapter along with their importance to this project. 2.1 Ptrace Ptrace stands for “Process Trace” and is one of the system calls available in UNIX and other UNIX related operating systems. It provides control over the execution of some other process to be traced. Most sophisticated tracing tools use ptrace underneath. Ptrace can be configured to get control for every system call made by the process to be traced. Once it gets control, it can read or modify the register contents and decide on the further action. Several security tools use ptrace for systematic execution and debugging of a process to be traced. There are two ways of tracing a process using ptrace. One, the parent process can fork to spawn a new child and later the child can do a PTRACE_TRACEME followed by exec [3][4]. The other way is the parent process can trace an existing process using PTRACE_ATTACH. The child process being traced stops at every signal even if the signal is set to be ignored. There is an exception for this due to SIGKILL. The parent process gets control at its next “wait” and can read or modify the register contents. Further, it can continue the execution of the child process by optionally ignoring the delivered signal or can terminate the child using PTRACE_KILL, if 6 required. Once tracing is completed, the parent process can release the control over the child using PTRACE_DETACH. 2.2 Systrace Systrace is one of the computer security tools for controlling the execution of a child process. It enforces certain policy for the process under trace. For every system call made by the process, systrace checks if it is permitted in the policy or not. If denied, the execution of the system call will be rejected, further any remaining unexecuted system calls will also be automatically rejected, and behavior of the code becomes unpredictable due to these rejects. A user can configure systrace to generate a policy for a particular binary. Once generated, the user can edit it to allow and deny certain system calls based on the requirement. Later, systrace can use the modified policy to run the binaries and can check for any violation. The system calls not covered in this policy are denied. In a distributed environment, an arbitrary process can be monitored remotely from central location using systrace. If an intrusion occurs into any remote machine, systrace catches it and prevents the intrusion from making further damage to the system. Systrace also provides support for interactive policy generation, where every system call and their parameters that are not covered in the current policy will be displayed in a GUI. The user can edit them, which in turn updates the current policy to either allow or deny the new system call [5][6]. 2.3 Strace Strace is a powerful debugging utility tool available for linux and other unix related operating systems. It intercepts and records all the system calls made by a particular process along with the 7 signals the system calls receive. Strace logs all the necessary information regarding the system call, the parameters and return values, on to the standard error by default or into a specified file. As a debugging tool, strace can be used to analyze any process that frequently crashes. Strace will print every system call made by the process, which can be used for debugging. For example, a process may try to access a file that is not present. This error checking might not have been taken care in the program. Therefore, the compiled binary will crash every time when it tries to open the file. Such scenarios can be debugged using strace, which prints the information about the file’s read system call along with the arguments used [7] [4]. 2.4 Ktrace Ktrace, which means kernel trace, is a utility available with Mac OS X and some Unix related operating systems. It is used to document the interaction of the kernel with a particular process. Therefore, it can log the system calls, signal processing and I/O of a particular process. The working of ktrace is similar to strace of Linux but much faster because strace has to deal with context switching every time it traces a system call. While in ktrace, there are no additional context switches as the kernel itself logs the required information [4]. 2.5 Conclusion This project requires a security tool that can monitor every system call and log them in a file that can be viewed and edited by a human. Once required information regarding permitted and denied system calls is entered, the security tool should work independent of the human aid. The entire application must be automated with no human interaction. 8 Strace, Ktrace and other security tools are very helpful while debugging a process. However, they will not be able to control the execution of the process based on a list of allowable and denied system calls. Ptrace can get control every time the child process makes a system call. However, requires a lot of coding to check and compare every system call. It also requires repeated ptrace calls to communicate between parent and child process. It only provides basic controlling features and requires some OS specific knowledge to work on it. Systrace suits the current requirement of this project. It accomplishes the task of monitoring system calls using a policy mechanism. First, the policy will be generated by systrace itself. Once generated, the user can read the policy, edit it to permit and deny certain system calls as per requirement, and hand it over back to systrace. Now systrace will only allow those system calls that are permitted in policy and the rest will be denied. If any system call is denied, it will log the details in a file, which can be referred by the user. So, I will be using the systrace tool to implement a Security Sandbox PC2 in this project [5][6]. 9 Chapter 3 WORKING WITH SECURITY TOOLS Before implementing a Security Sandbox using systrace to monitor C/C++ programs, it is necessary to get a good hands-on experience with systrace. Systrace uses underlying ptrace for tracing system calls. Therefore, a better understanding of how ptrace works is equally important. This will give a good knowledge about how ptrace and systrace monitor system calls, their required environment, input parameters, result of their implementation, ways to utilize the features of these tools, and several others so that they can be successfully integrated into this project. 3.1 Ptrace Implementing ptrace involves a parent process and a child process. Child process needs to request its parent to trace it by using PTRACE_TRACEME. Below is a simple program to describe the working of basic ptrace commands. In this example, the parent spawns a child process. The child process can be any program, which has a PTRACE_TRACEME instruction in the beginning. ptrace.cpp #include #include #include #include #include #include <sys/ptrace.h> <sys/types.h> <sys/wait.h> <stdio.h> <unistd.h> <sys/reg.h> struct user_regs_struct{ unsigned long ebx; unsigned long ecx; unsigned long edx; unsigned long esi; unsigned long edi; 10 unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned }uregs; long long long long long long long long long long long long ebp; eax; ds; es; fs; gs; orig_eax; eip; cs; flags; esp; ss; int main() { pid_t child; long orig_eax; child = fork(); if(child == 0) { ptrace(PTRACE_TRACEME, 0, NULL, NULL); execl("/bin/ls", "ls", NULL); } else { wait(NULL); orig_eax = ptrace(PTRACE_PEEKUSER, child, 4*ORIG_EAX, NULL); printf("The child made a system call %ld\n", orig_eax); ptrace(PTRACE_GETREGS, child, 0, &uregs); printf("Register contents: \n"); printf("EAX = %ld\n", uregs.eax); printf("EBX = %ld\n", uregs.ebx); printf("ECX = %ld\n", uregs.ecx); printf("EDX = %ld\n", uregs.edx); printf("ESI = %ld\n", uregs.esi); printf("EDI = %ld\n", uregs.edi); printf("EBP = %ld\n", uregs.ebp); printf("DS = %ld\n", uregs.ds); printf("ES = %ld\n", uregs.es); printf("FS = %ld\n", uregs.fs); printf("GS = %ld\n", uregs.gs); printf("ORIG_EAX = %ld\n", uregs.orig_eax); printf("EIP = %ld\n", uregs.eip); printf("CS = %ld\n", uregs.cs); printf("FLAGS = %ld\n", uregs.flags); 11 printf("ESP = %ld\n", uregs.esp); printf("SS = %ld\n", uregs.ss); ptrace(PTRACE_CONT, child, NULL, NULL); } return 0; } Output: The child made a system call 11 Register contents: EAX = 0 EBX = 0 ECX = 0 EDX = 0 ESI = 0 EDI = 0 EBP = 0 DS = 123 ES = 123 FS = 0 GS = 0 ORIG_EAX = 11 EIP = 12613712 CS = 115 FLAGS = 2097682 ESP = -1080493648 SS = 123 Debug src In this program, the structure “user_regs_struct” is defined to accumulate the register information and other required details from the system call. The ordering of the registers in the structure “uregs” is based on i386 architecture. The parent process forks the child, which executes a “execl” system call. Before calling this system call, the child requests the parent to trace it by using PTRACE_TRACEME. This informs the kernel that its parent process is tracing the child process. Therefore, whenever the child executes a system call, the kernel hands over the control to parent process. The parent waits for a signal from kernel by issuing a wait() command. Once the parent gets control, it can check the 12 system call information and can read the register contents. Further, the parent process can even edit the register contents. The first line in the output of the above program indicates the system call number 11, which is same as the system call number of “execv”. The rest of the output shows the content of the child’s registers for that particular system call. Since the child tried to execute “ls” command, the last line in the output displays the content of the child’s current directory [8]. 3.2 Systrace Working with systrace can be categorized into two parts. In the first part, an executable binary is handed over to systrace to run and generate a policy file [5][6][9]. To demonstrate this, consider a simple C++ program as below [10]. testsystrace.cpp #include <stdio.h> #include <stdlib.h> #include <sys/reg.h> #include <unistd.h> #include<sys/socket.h> int main() { int listenFd; getppid(); listenFd = socket(AF_INET, SOCK_STREAM, 0); getpid(); return 0; } The above program contains mainly three system calls: getppid, socket and getpid. Once compiled the binary file is given to systrace as one of its input parameters. 13 systrace –A home/site1/workspace/testsystrace/Debug/testsystrace The input parameter “-A” indicates to systrace to generate the policy for the binary file named “testsystrace”. Now, systrace executes the binary and generates the policy file as shown below. linux-getppid: permit linux-socket: sockdom eq "AF_INET" and socktype eq "SOCK_STREAM" then permit linux-getpid: permit The generated policy will be present in the .systrace directory. The naming convention for the generated policy file is equal to the path name of the binary file with “/” replaced by “_”. In this example, the resulting policy file name looks like “home_site1_workspace_testsystrace_Debug_testsystrace”. In the next run, the generated policy can be given as input to systrace as shown below. systrace –a home/site1/workspace/testsystrace/Debug/testsystrace The input parameter “-a” indicates systrace to consider the policy which is already present. If the location is not specified in the command (as shown in the above example), then by default systrace searches in .systrace directory. When executed, systrace will not generate any logs as no system call is being denied by the permissions in the specified policy file. The user can edit the policy file and change the permissions as per the requirements. In this example, the user can deny the execution of “getpid” by removing “getpid” permission from the policy file. The new policy file is as shown below. 14 linux-getppid: permit linux-socket: sockdom eq "AF_INET" and socktype eq "SOCK_STREAM" then permit Now, systrace is executed with the new updated policy file. The new systrace command is as shown below. systrace –a home/site1/workspace/testsystrace/Debug/testsystrace –D home/site1/workspace/testsystrace/Debug –E home/site1/workspace/testsystrace/Debug/systrace.txt \ \ The “-D” option mentions the place where the systrace has to look for the policy file. The “-E” informs systrace regarding where to create the log file generated if there are any denied system calls. Execution of above systrace command results in a log file by name “systrace.txt” in “home/site1/workspace/testsystrace/Debug” folder with contents as shown below: systrace: deny user: root, prog: home/site1/workspace/testsystrace/Debug/testsystrace, pid: 10657(0)[0], policy: home/site1/workspace/testsystrace/Debug/testsystrace, filters: 364, syscall: linux-getpid(20), args: 68 \ \ \ \ Using the log file, the user can check the reason for denying the execution of the binary file and can take appropriate action. The above commands will be used in this project to monitor system calls by sandboxing the execution of C/C++ binary files using systrace. The Java Security tools that will be used in the Sandbox to monitor Java programs are explained in the later chapters. 15 Chapter 4 SECURITY APPROACH FOR PROGRAMMING LANGUAGES 4.1 With C/C++ Linking required directories and libraries, and compiling C/C++ file results in a binary executable, which can be used in systrace. Therefore, it is necessary to have a C/C++ binary executable file that invokes every known system call. Systrace takes this binary file and generates a C/C++ base policy file that consists of a list of permitted system calls used in that C/C+ program. Since the C/C++ program contained call to every system call, the systrace generated base policy file would cover access to most libraries and permissions to execute every system call. However, the judge would come up with a policy file that specifies a list of permitted system calls for that contest or for a particular problem. Only these system calls are need to be present in the systrace policy file. Hence, the generated systrace base policy file needs to be edited to include only judge’s permitted system calls. The contest administrator can edit the base policy as per the requirements of the contest and the current programming problem. By referring to the judge’s given policy file, the administrator can retain only the required system call permissions and remove the rest. The updated policy file now contains a list of permitted system calls, which can be directly used on the participant submitted C/C++ program. Systrace only permits the system calls that are present in the input policy. If the submitted program tries anything illegal then systrace will deny the execution of that particular system call and will terminate the execution of the program. The denied system calls will be logged and a judge or an administrator can look into them to take necessary actions. By using a base C/C++ policy file common to all the contest’s C/C++ problems, the path to achieve the security sandboxing of the C/C++ programs can be made easier. 16 4.2 With Java Systrace can be used to achieve security sandboxing for only binary executables. In the case of Java, the program is compiled to a .class file, which can be executed only through use of a Java Virtual Machine (JVM). This means that systrace cannot be directly used on Java programs. There are different ways to sandbox a Java program. By creating a C/C++ program that invokes a Java program through Java Native Interface (JNI), Java programs can be monitored using systrace. One more approach would be using Java security manager class. These two approaches are explained in the following sections. 4.2.1 Using C/C++ with JNI To implement security sandboxing for Java, one of the approaches to tackle the problem between binary executables and JVM is by calling a Java program from a C++ program. This C++ program would create a JVM and call the main method inside the Java class. Now the binary executable of the C++ program can be used in systrace to achieve the Security Sandbox environment. The C/C++ program that creates a JVM and invokes a Java program is as shown below [11]. C2java.cpp: #include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<sys/socket.h> #include <sys/ptrace.h> #include <sys/wait.h> #include <unistd.h> #include <sys/reg.h> #include <iostream> #include "jni.h" #include "jni_md.h" 17 #include <jvmti.h> #include <iostream> using namespace std; int main() { JNIEnv *env; JavaVM *jvm; JavaVMInitArgs vm_args; jint res; jclass cls; JavaVMOption options; options.optionString = "Djava.class.path=/home/site1/workspace/myjava"; vm_args.version = JNI_VERSION_1_6; //JDK version. This indicates version 1.6 vm_args.nOptions = 1; vm_args.options = &options; vm_args.ignoreUnrecognized = 0; JNI_GetDefaultJavaVMInitArgs(&vm_args); /* Create JVM */ res = JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args); /* Get Class ID */ cls = env->FindClass("myjava"); if (cls == 0) printf("Sorry, Not able to find the class\n"); /* Get Static Main method ID */ jmethodID get_main_id = env>GetStaticMethodID(cls,"main","([Ljava/lang/String;)V"); if (get_main_id == NULL) printf("Sorry, Not able to find the main\n"); env->CallStaticVoidMethod(cls, get_main_id); /* Destroy JVM */ jvm->DestroyJavaVM(); return 0; } 18 Before creating a JVM, the required information including JDK version and Java class name to be called must be entered. The JVM is created by executing the command JNI_CreateJavaVM. “FindClass” is used to get the class ID. Using Class ID, “GetStaticMethodID” is used to obtain the main method’s ID, by sending the signature information including the arguments and return value. Once the method ID is received, “CallStaticVoidMethod” is used to invoke the Java program’s main method. Now, the compiled binary of this C++ program can be used in systrace. If the Java program makes any system call, systrace can catch that and verify it against the policy file. However, the above approach has some disadvantages. The systrace policy file generates a huge number of file reads into JVM libraries. This becomes difficult to differentiate between file reads by JVM and the ones made by the actual Java program. Therefore, this method is not suitable for implementing in a programming contest. 4.2.2 Using Java Security Manager Java has a built-in security manager which can restrict access control such as reading from or writing into files, accessing system properties, socket programming, networking, AWT, serializable, reflective operations, runtime commands, SQL and SSL methods, and etc., [12][13]. The SecurityManager class is used to implement the security restrictions. An instance of this class can be accessed through System.getSecurityManager() method. If no security manager were registered, then instance would return a null. Moreover, a policy file can be created which contains all the necessary security permissions. The security manager can use this policy to restrict permissions on a particular Java program. The Security manager by default denies permissions to all those operations that are not mentioned in the given input Java policy file. Hence, an empty block as shown below will simply deny everything. 19 grant{ }; Before utilizing this feature, the program needs to the inform JVM about its intentions of using Security Manager. This can be achieved by a command line argument, which also mentions the policy file “test.policy” to be used. The compiled .class file is kept inside a jar file and executed as shown below. java -Djava.security.manager -Djava.security.policy=test.policy –jar asimplejava A simple file operation using Java with security manger enabled is explained below. The program tries to write into a file called “filename.txt”. The scenario is explained with and without a grant permission set in the policy file. asimplejava.java: import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; public class asimplejava { public static void main(String[] args) throws IOException { FileWriter outFile = new FileWriter("filename.txt"); PrintWriter out = new PrintWriter(outFile); out.println("Testing Java Security Manager"); out.close(); System.out.println(“File written successfully”); } } Output: File written successfully 20 The above program successfully executes since there is no security manager enabled. Now, enable the security manager and use the “test.policy” policy file as shown below. Since there are no permissions mentioned in the grant block, by default it will deny all the permissions. grant{ }; Now, when the program is executed using the policy file, the output can be observed as follows. Exception in thread "main" java.security.AccessControlException: access denied (java.io.FilePermission filename.txt write) at java.security.AccessControlContext.checkPermission(AccessControlContex t.java:323) at java.security.AccessController.checkPermission(AccessController.java:5 46) at java.lang.SecurityManager.checkPermission(SecurityManager.java:532) at java.lang.SecurityManager.checkWrite(SecurityManager.java:962) at java.io.FileOutputStream.<init>(FileOutputStream.java:169) at java.io.FileOutputStream.<init>(FileOutputStream.java:70) at java.io.FileWriter.<init>(FileWriter.java:46) at asimplejava.main(asimplejava.java:10) The security manager throws an access denied exception for the file write to “filename.txt”. This is because, once the policy is specified, the security manager checks the policy file to see which permissions are allowed. In the above scenario, there is no permission for writing into “filename.txt”. Hence, it throws an AccessControlException with denied file write permission for “filename.txt”. The permission can be granted as follows. 21 grant{ permission java.io.FilePermission "filename.txt", "write"; }; The permission to write into “filename.txt” is granted to the Java program. The outcome of the execution is as follows. File written successfully Choosing the appropriate permissions for running a Java program is necessary for controlled sandboxing. Therefore, for this project, security sandboxing will be different for C/C++ and Java programs. Systrace will be used for sandboxing C/C++ programs and Java security manager for Java programs. 22 Chapter 5 SOFTWARE DESIGN AND APPROACH 5.1 Design Flow The design of the project centers around two primary modules: Generate and Execute. The Generate module takes problem number, judge’s policy file and base policy file to generate C/C++ and Java policy files. These files would be used in the Execute module for running C/C++ and Java programs. Invoke Judge or Administrator PC^2 Problem Specific Judge Policy Problem # C/C++ Base Policy Generate Problem Specific Executable File Problem Specific Output Log File Name Indicator for C/C++ and Java Invoke Execute No Yes Security Violation Print: Security Violation: Reason Print: No Security Violation Read Output Log File Problem Specific C/C++ or Java Policy File Problem Specific Output Log File Figure 1 Complete Flow 23 This section explains the flow of the project with detailed information about every block and module, input and output files, which are used during the execution of Generate and Execute module. 5.1.1 Judge or Administrator This represents a judge or an administrator who takes care of setting up the Sandbox environment. They supply problem number, contest or problem specific judge policy file and a C/C++ base policy file to the Generate module. Now, a judge or an administrator invokes the Generate module to generate a C/C++ and Java policy files specific to the contest or to the problem. 5.1.2 Problem # The specific problem number of the programming contest. Generally, it would be A, B, C … 5.1.3 Problem Specific Judge Policy Judge or Administrator’s policy file that contains information regarding allowable system calls. This policy can be used as a common policy for every problem or for a particular one. 5.1.4 Base Policy Policy file generated by running C/C++ code that contained every possible system calls. This policy will be used to catch libraries that will be accessed while running a C/C++ binary. 5.1.5 The Generate Module This module generates C/C++ and Java policy files for every contest problem. 24 5.1.6 Problem Specific Executable File The compiled binary file of participant’s C/C++ code or a .class file of participant’s Java code. 5.1.7 Problem Specific C/C++ Policy File The policy file relative to a particular contest’s problem. This will be generated as the output of the Generate module and later used by the Execute module for running the participant’s code. 5.1.8 Problem Specific Output Log File Name This represents the file name to be used for creating an output log file. This log file will be created by the Execute module as a result of its execution. PC2 will refer to this problem specific output log file by its name, to check for any security violation. 5.1.9 Indicator for C/C++ and Java A string input for the Execute module for indicating whether the incoming executable is a C/C++ binary or a .class file. 5.1.10 The Execute Module Executes the binary file or .class file using a policy file and generates the output log file. 5.1.11 Security Violation Checks if there was any violation and logs the message into output log file accordingly. 25 5.1.12 Print: No Security Violation Stores “No Security Violation” data inside the output log file. 5.1.13 Print: Security Violation with reason Stores the information regarding security violation in output log file, which occurred during the execution of the participant’s code. 5.1.14 Output Log file This file is generated after the execution of participant’s code. This file contains the information about any security violation that might have occurred during the execution. Else, it contains a “No Security Violation” tag. 5.1.15 PC2 The main PC2 tool that invokes the Execute module by providing the necessary input files and information. This also reads the output log file generated by the Execute module for any security violation and takes corresponding action. 5.2 The Generate Module The Generate module will be executed only once at the beginning of the contest, to generate the policies. This module goes through the judge’s policy files corresponding to the contest or a particular problem and translates it to C/C++ and Java policy files. The generated policy files are problem specific. There will be a C/C++ policy and a Java policy for every problem in the contest. 26 For C/C++, the Generate module also refers to the base policy file that contains every system call information and required library paths, in a systrace friendly format. Information on all available libraries is taken from the base policy and written into C/C++ policy file. Later, the Generate module uses judge’s policy file, maps it to systrace format and writes into C/C++ policy file. For Java, the Generate module maps the judge’s policy file into a Java policy file. Here, extra care has to be taken to translate into Java friendly policy format. A good understanding of Java policies and Security Manager is required for successful implementation. Java has limited features to perform system calls. So, not all Judges’ policies can be mapped. Certain system calls require some work around to be done before they can be mapped into Java. For example, to execute “ls” command in Linux, C/C++ can accomplish by simply forking a child process and running “execve”. By providing permissions for “fork” in the judge’s policy file, the C/C++ can easily execute “ls” command. However, Java needs to go through “Runtime” class and “exec” method and has a different approach for executing the “ls” command. It needs to invoke “/bin/ls” file to run “ls” command. Hence, permission to execute the file “/bin/ls” needs to be provided. Since, there is only one Judge Policy file used to generate both C/C++ and Java policy, the Generate module needs to do the above-mentioned workaround to provide permissions in both C/C++ and Java. The final output of this module consists of a C/C++ and a Java policy file. 5.3 The Execute Module PC2 uses the generated policies as input to run the Execute module. In the case of C/C++, PC2 supplies either a binary executable or a Java .class file to the Execute module, an indicator to differentiate between C/C++ and Java, the policy file to be used, and the output log file name. After providing the necessary inputs, PC2 invokes the Execute module. 27 To simplify the execution flow, a simple shell script called “run_execute.sh” is used which is wrapped around the Execute module. This shell script accepts the exact input parameters required by the Execute module and passes them to it. The “run_execute.sh” script also serves the purpose of finding whether the participant’s code should run using the Sandbox or not. The Security Sandbox will only be present on Judge’s machines and not on participant’s machines. Since the participant’s test run would happen on his or her own machines that does not require the Sandbox, the “run_execute.sh” script would simply run their program without checking for any security violations. However, the “run_execute.sh” script uses the Security Sandbox to run participant’s code on a Judge’s machine. The “run_execute.sh” script decides whether to run the Sandbox by checking if the Execute module is present in the executable path or not. If it is present then the “run_execute.sh” script uses the Sandbox. Otherwise, it runs the participant’s code directly with no security checks. Hence, to accomplish the above purpose, the Security Sandbox including the Execute module, would be deployed only on the Judge or Administrator’s machine and not on the participant’s machine. 28 Problem specific binary image Indicator for C/C++ Problem specific systrace Policy File Problem specific OutPut Log File Name Invoke Execute Problem specific systrace Policy File Problem specific binary file Temporary Output Log File Systrace Yes No Security Violation Run C/C++ Binary Print: Security Violation: Reason Print: No Security Violation Output Log File Figure 2 C/C++ Execution Flow For C/C++ programs (See Figure 2), the Execute module uses the input policy file and executable binary, and invokes systrace with this information. Systrace runs the binary executable against the given policy and logs information about violation if any occurred, in a temporary output log file. The Execute module reads the temporary output log file to check if there was any security 29 violation. If there was no violation, the Execute module simply says “No Security Violation” and logs it in Judge’s output log file. PC2 refers into the log file and takes appropriate action. Problem specific .class file Problem specific OutPut Log File Name Problem specific Java Policy File Indicator for Java Problem specific .class file Problem specific Java Policy File Temperary Output Log File Create Invoke Execute Invoke Java Wrapper JVM (With Java Security Manager) No Security Violation (Access Control Exception) Print: Security Violation: Reason Print: No Security Violation Problem specific Output Log File Figure 3 Java Execution Flow Yes 30 In the case of Java (See Figure 3), the Execute module uses input Java policy file and creates a Java wrapper module. This wrapper creates a JVM to invoke the given .class file. It also informs JVM to enable Security Manager and use the given input policy file to check for security violation. If there was any security violation, security manager terminates the execution of the .class file and throws an access denied exception. Java wrapper catches the exception and logs an appropriate message into the output log file that will be later referred by the Judges. If there was no access denied exception, “No Security Violation” message will be logged. 31 Chapter 6 EXAMPLES OF SECURITY VIOLATION ATTEMPTS There are several ways a hacker can attempt to breach through the security of PC2. They can try to execute system calls that can bring down the entire PC2 system, or try to establish a socket connection to send across some important files related to the PC2 or to the programming contest. Most of the system calls attempted through a C/C++ code can be easily caught by systrace. When it comes to Java, it lacks many features regarding system calls that a C/C++ program enjoys. Hence, it is not easy to perform system calls in Java. However, a Java program can execute system calls using the “exec” method and JNI, and care has to be taken when such attempts are made. This section explains some of the anticipated attempts that a hacker can try to execute. It also demonstrates the results of such attempts when the Security Sandboxing is used. 6.1 Execution of system calls by Java using exec method The Java “exec” method can call any executable file present on the system. The following example illustrates a Java class that attempts to execute the “ls” command through the “exec” method with the Security Manager enabled and along with a Java policy file. The Java Security Manager catches the access denied exception for trying to execute the “ls” command. javaexec with policy file enabled: public class javaexec { public static void main(String[] args) { try{ String str = null; Runtime runtime = Runtime.getRuntime(); Process process = runtime.exec("/bin/ls"); InputStream is = process.getInputStream(); InputStreamReader isr = new InputStreamReader(is); 32 BufferedReader br = new BufferedReader(isr); while((str = br.readLine()) != null){ System.out.println(str); } } catch(Exception e){ e.printStackTrace(); } } } Output: java.security.AccessControlException: access denied (java.io.FilePermission /bin/ls execute) at java.security.AccessControlContext.checkPermission(AccessControlContex t.java:323) at java.security.AccessController.checkPermission(AccessController.java:5 46) at java.lang.SecurityManager.checkPermission(SecurityManager.java:532) at java.lang.SecurityManager.checkExec(SecurityManager.java:779) at java.lang.ProcessBuilder.start(ProcessBuilder.java:448) at java.lang.Runtime.exec(Runtime.java:593) at java.lang.Runtime.exec(Runtime.java:431) at java.lang.Runtime.exec(Runtime.java:328) at javaexec.main(javaexec.java:11) 6.2 Execution of System calls by Java using JNI A participant can submit Java code along with a C/C++ binary file. The submitted Java code can try calling the binary file through JNI. However, such JNI calls also get caught by the security manager. An access denied exception is thrown for attempting to load a JNI library during run time. The following example shows how Java code can try to call a binary file and gets caught by the security manager [14]. 33 Java Code with policy file enabled: public class HelloWorld{ private native void print(); public static void main(String[] args) { new HelloWorld().print(); } static{ System.loadLibrary("HelloWorld"); } } C Code: #include "jni.h" #include <stdio.h> #include "HelloWorld.h" JNIEXPORT void JNICALL Java_HelloWorld_print(JNIEnv *env, jobject obj) { printf("Hello World!\n"); printf("PID: %d\n",getpid()); return; } Output: java -Djava.security.manager -Djava.security.policy=java.policy -jar HelloWorld.jar Exception in thread "main" java.lang.ExceptionInInitializerError Caused by: java.security.AccessControlException: access denied (java.lang.RuntimePermission loadLibrary.HelloWorld) at java.security.AccessControlContext.checkPermission(AccessControlContex t.java:323) at java.security.AccessController.checkPermission(AccessController.java:5 46) at java.lang.SecurityManager.checkPermission(SecurityManager.java:532) at java.lang.SecurityManager.checkLink(SecurityManager.java:818) at java.lang.Runtime.loadLibrary0(Runtime.java:817) at java.lang.System.loadLibrary(System.java:1028) at HelloWorld.<clinit>(HelloWorld.java:8) Could not find the main class: HelloWorld. Program will exit. 34 6.3 Java socket connection One of the important aspects that need to be considered during security is socket connection. The Java code can try to establish a client socket connection that may simply transfer files to a host or target computer. Security manager can curb such attempts and throw access denied exception for socket permissions. The following code illustrates a simple client-server Java application [15][16]. When client code is executed, the security manager throws an exception for using “connect and resolve”. In addition, for the server code, it throws an exception for using “accept and resolve”. VerySimpleServer.java: import import import import import java.net.Socket; java.net.ServerSocket; java.io.InputStream; java.io.OutputStream; java.io.IOException; public class VerySimpleServer { private static int serverPort = 8085; private static ServerSocket serverSock = null; static Socket sock = null; static InputStream sockInput = null; static OutputStream sockOutput = null; static byte[] buf=new byte[1024]; static int bytes_read = 0; public static void main(String argv[]) { try { serverSock = new ServerSocket(serverPort); sock = serverSock.accept(); sockInput = sock.getInputStream(); sockOutput = sock.getOutputStream(); bytes_read = sockInput.read(buf, 0, buf.length); System.out.println("Received: "+buf); sockOutput.flush(); sock.close(); } catch (IOException e){ 35 e.printStackTrace(System.err); } } } VerySimpleClient.java: import import import import import java.net.Socket; java.net.ServerSocket; java.io.InputStream; java.io.OutputStream; java.io.IOException; public class VerySimpleClient { private static byte[] data = "Hello World".getBytes(); private static Socket sock = null; private static InputStream sockInput = null; private static OutputStream sockOutput = null; static byte[] buf = null; static int bytes_read = 0; public static void main(String argv[]) { try { printf(“Opening connection to localhost port 8085\n”); sock = new Socket("localhost", 8085); sockInput = sock.getInputStream(); sockOutput = sock.getOutputStream(); System.out.println("Sending: "+data); sockOutput.write(data, 0, data.length); sock.close(); } catch (IOException e){ e.printStackTrace(System.err); } } } Policy Applied on Client code: Opening connection to localhost port 8085 Exception in thread "main" java.security.AccessControlException: access denied (java.net.SocketPermission 127.0.0.1:8085 connect,resolve) at java.security.AccessControlContext.checkPermission(AccessControlContex 36 t.java:323) at java.security.AccessController.checkPermission(AccessController.java:5 46) at java.lang.SecurityManager.checkPermission(SecurityManager.java:532) at java.lang.SecurityManager.checkConnect(SecurityManager.java:1034) at java.net.Socket.connect(Socket.java:524) at java.net.Socket.connect(Socket.java:478) at java.net.Socket.<init>(Socket.java:375) at java.net.Socket.<init>(Socket.java:189) at VerySimpleClient.sendSomeMessages(VerySimpleClient.java:24) at VerySimpleClient.main(VerySimpleClient.java:73) Policy Applied on Server Code: Exception in thread "main" java.security.AccessControlException: access denied (java.net.SocketPermission 127.0.0.1:46200 accept,resolve) at java.security.AccessControlContext.checkPermission(AccessControlContex t.java:323) at java.security.AccessController.checkPermission(AccessController.java:5 46) at java.lang.SecurityManager.checkPermission(SecurityManager.java:532) at java.lang.SecurityManager.checkAccept(SecurityManager.java:1157) at java.net.ServerSocket.implAccept(ServerSocket.java:457) at java.net.ServerSocket.accept(ServerSocket.java:421) at VerySimpleServer.waitForConnections(VerySimpleServer.java:72) at VerySimpleServer.main(VerySimpleServer.java:107) 6.4 C/C++ socket connection When a program attempts to establish client-server connection, the systrace policy file can easily prohibit such actions. The following examples contain a simple client code, a simple server code and the results of executing each code using systrace policy [17]. 37 During execution of client and server code, systrace restricts the use of socket related system calls, as the permissions to execute them are not present in the C/C++ policy file. To enable this, the administrator or the judge has to permit the use of such system calls in the policy file. asimpleclient.cpp: #include #include #include #include #include #include #include #include #include #include <iostream> <stdio.h> <stdlib.h> <unistd.h> <sys/types.h> <sys/socket.h> <netinet/in.h> <error.h> <string.h> <netdb.h> #define PORT 0x8093 #define DIRSIZE 8192 #define HOST 127.0.0.1 using namespace std; int main(int argc, char *argv[]) { char dir[8192]; int sd, sd_current, cc, fromlen, tolen; int addrlen; struct sockaddr_in sin; struct sockaddr_in pin; struct hostent *hp; char hostname[100]; strcpy(hostname, "127.0.0.1"); hp = gethostbyname(hostname); memset(&pin, 0, sizeof(pin)); pin.sin_family = AF_INET; pin.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr))->s_addr; pin.sin_port = htons(PORT); sd = socket(AF_INET, SOCK_STREAM, 0); connect(sd, (struct sockaddr *) &pin, sizeof(pin)); 38 send(sd, "Sandbox",strlen("Sandbox"), 0); printf("Sending: %s\n","Sandbox"); return 0; } asimpleserver.cpp: #include #include #include #include #include #include #include #include #include #include <iostream> <stdio.h> <stdlib.h> <unistd.h> <sys/types.h> <sys/socket.h> <netinet/in.h> <error.h> <string.h> <netdb.h> #define PORT 0x8093 #define DIRSIZE 8192 using namespace std; int main(int argc, char *argv[]) { char dir[8192]; int sd, sd_current, cc, fromlen, tolen; int addrlen; struct sockaddr_in sin; struct sockaddr_in pin; sd = socket(AF_INET, SOCK_STREAM, 0); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(PORT); bind(sd, (struct sockaddr *) &sin, sizeof(sin)); listen(sd, 5); addrlen = sizeof(pin); sd_current = accept(sd, (struct sockaddr *) &pin, (socklen_t*)&addrlen); recv(sd_current, dir, sizeof(dir), 0); printf("Receiving: %s\n",dir); 39 close(sd_current); close(sd); return 0; } Policy Applied on Server Code: syscall: linux-socket(102), sockdom: AF_INET, socktype: SOCK_STREAM Policy Applied on Client Code: syscall: linux-socket(102), sockdom: AF_INET, socktype: SOCK_STREAM 6.5 Forking child process in C/C++ Another example of a system call which might be attempted in a programming contest is “fork”. However, if the permissions to “clone” or “fork” is process is not allowed in the C/C++ policy file, systrace will reject the creation of a child process. The following example demonstrates a program trying to fork a child process. Assuming that input C/C++ policy file does not permit “clone” or “fork” system calls, systrace denies the creation of a child process. fork.cpp: #include #include #include #include #include #include <iostream> <stdio.h> <stdlib.h> <string.h> <unistd.h> <sys/wait.h> using namespace std; int main() { 40 pid_t pid_child; int status; printf("Before Cloning\n"); pid_child = fork(); if(pid_child == 0){ printf("Inside Child process\n"); exit(0); } else{ wait(&status); } printf("After Cloning\n"); return 0; } Since there was no permission specified to allow “clone” system call, systrace rejects the execution and the resulting output is shown below. Policy Applied on fork.cpp Code: Security Violation: syscall: linux-clone(120), args: 68 6.6 Assumptions and Limitations The Security Sandbox entirely depends on systrace for controlling the execution of C/C++ binary and Java Security Manager for execution of Java code. Both systrace and security manager have some limitations and they are also applicable for the Sandbox. Most anticipated malicious attempts have been tested and the Sandbox has shown good results by restricting them. However, new unknown attempts can be made to breach through the system. The Sandbox needs to be periodically updated to restrict such attempts. 41 For executing a Java code, the required .class files will be kept inside jar file, along with a manifest file. Java security manager is applicable on jar file and not Java. However, when tried directly on Java .class file, certain permissions were ignored and the security manager allowed access to some files. There is no proper explanation for using a jar file and not directly Java. In this project, the Execute module creates a jar file and keeps the required .class files in it. Once a jar file is created, security manager is invoked on jar file. For C/C++, systrace can use the user-defined policy to execute and monitor on the binary file. This can be achieved by using “-d” to mention systrace about the location of the policy file. However, while using systrace, certain naming convention needs to be followed. When using “d” option, the complete path name of the directory which contains policy file must be given. This path name should not contain the name of the policy file. Systrace searches for the policy file in the specified directory. Hence, the policy file must also follow certain naming convention. For an executable file, the policy name is equal to the directory path of the executable binary including the name of the binary at the end. All “/” should be replaced with “_”. For example, if the binary file “cbinary” is present in “home/username/workspace/workingdir” directory, then the policy file name must be named as “home_username_workspace_workingdir_cbinary”. This has to be followed if systrace is used. Therefore, in this project, the Generate module simply generates the required policy file. The user, while invoking the Execute module to run C/C++ binary, needs to mention the problem letter or number, in order to access that particular policy file. The Execute module will take the given policy file name, search for it in the sandbox directory and create its own copy in the current working directory. While creating the copy in the current working directory, the Execute module makes necessary changes inside the policy file to reflect current working directory and 42 executable binary. The naming convention will be taken care of by the Execute module. It reads the current working directory name and appends the binary file name at the end. Once the input policy file is created in a required format, the Execute module takes care of applying it on the participant’s program. 43 Chapter 7 DEPLOYMENT AND TESTING OF THE SANDBOX IN PC2 The previous chapters discussed the development and testing of the Sandbox outside PC2. Testing provided good results for most anticipated sorts of malicious code. Considering these test results, the Sandbox needs to be deployed inside PC2 and has to be tested as one system. This chapter discusses the best way to deploy Sandbox inside PC2 and the changes required for making team runs. 7.1 Executing team runs with no Sandbox For Java, PC2 compiles the code into a .class file and executes it by creating and running a JVM. The following illustrates a list of commands for running Java program in PC2. 1. Compile Cmd Line: javac {:mainfile} 2. Executable Filename: {:basename}.class 3. Program Execution Command Line: java {:basename} PC2 substitutes the variables for {:mainfile} and {:basename}. Once compiled, the {:basename}.class file will be created. Finally, PC2 executes the .class file and either displays the results on a small window or stores it in a file. The judges or an administrator verify these results and make decisions accordingly. For C/C++, PC2 compiles the submitted programs to an executable .exe binary file and later executes it to get the results. The series of commands used for compiling and running C/C++ files are as follows. 1. Compile Cmd Line (for C): Compile Cmd Line (for C++): gcc –lm –o {:basename}.exe {:mainfile} g++ –lm –o {:basename}.exe :mainfile} 44 2. Executable Filename: {:basename}.exe 3. Program Execution Command Line: ./{:basename}.exe The resulting output is compared and verified against the judge’s own copy and the decisions are made accordingly. 7.2 Setting Up Sandbox Environment and Executing with Sandbox Before executing the team runs, the Sandbox folder has to be kept in /usr/local/pc2v9/. Two executable files need to be present in an executable path so that they can be invoked from any location. The two executables include “execute” and “run_execute.sh”. “execute” is the binary executable of the Execute module and “run_execute.sh” is a shell program built over “execute” binary. Before invoking these executables, it is necessary to setup the Sandbox environment which includes generating a C/C++ base policy file, editing judge policy files and later generating problem specific Java and C/C++ policy files. 7.2.1 Generating a C/C++ Base Policy File for Systrace The Sandbox folder contains “generate.cpp” and “mysystemcalls.cpp” files. The “mysystemcalls.cpp” file contains code to invoke every available system call and the “generate.cpp” file is the source code for the Generate module. These two files can be compiled by running the “run_compile.sh” script. Now a C/C++ base policy file needs to be generated. This base policy file must contain permits to every system call and provide information about libraries referred for making these system calls. Since, the “mysystemcalls.cpp” program invokes every system call; by using systrace, this program can be used for generating a base policy file that contains permission to execute every system call. Therefore, a C/C++ base policy file can be created by issuing the command shown below. 45 sh run_compile.sh mysystemcalls base.policy Once a C/C++ base policy file is generated, the judge or contest administrator needs to set rules on making system calls. It can be done by specifying allowable system calls inside “judge.policy” file. This policy file will be in a XML format. 7.2.2 Modifying Judge Policy File Judge policy file is defined in a XML format to ease the editing process for an administrator or a judge. There is only one judge policy file for both C/C++ and Java. This helps a judge or an administrator to edit one policy for C/C++ and Java. The judge policy can be problem or contest dependent. There can be different policy files for different problems in the contest or just one for the whole contest. The Generate module will take a problem specific judge policy file and a C/C++ base policy file and generates a C/C++ systrace policy file and a Java policy file. The generated C/C++ policy will be used later by systrace to monitor a C/C++ binary executable and the generated Java policy file will be used later by Java security manager for monitoring a Java program. A typical judge policy file looks as shown below. <PERMIT> <FILE> fsread fileread.txt fswrite filewrite.txt </FILE> <TIME> </TIME> <SOCKET> </SOCKET> <SYSTEM> </SYSTEM> <JAVA-ONLY> </JAVA-ONLY> 46 </PERMIT> <!-- The following lists the names of the Linux system calls, together with the required parameters for each call, which the Judge can add to the <PERMIT> section shown above: Reference: Command + 3 Parameters: fchown fd uid gid Command + 2 Parameters: chmod filename mode fchmod fd mode kill pidname signame link filename1 filename2 mknod filename mode rename filename1 filename2 socket AF_INET<sockdom> SOCK_STREAM<socktype> Command + 1 Parameter: bind inet-[0.0.0.0]:32898 chdir directoryname chroot directoryname connect inet-[127.0.0.1]:32898<sockaddr> execve filename fsread filename fswrite filename mmap2 prot mprotect PROT_READ Command + no Parameter: accept acct adjtimex alarm bdflush brk chroot clone close creat dup 47 dup2 execve exit_group fchdir fchmod fchown fcnt164 fdatasync flock fstat64 fstatfs fsync ftruncate getcwd getdents getegid geteuid getgid getgroups getitimer getpigid getpgrp getpid getppid getpriority getresgid getresuid getrlimit getrusage getsid gettimeofday getuid ioctl ioperm iopl lchown listen llseek lseek mlock mlockall mremap mount msync munlock munlockall 48 munmap nanosleep newuname oldmount personality pipe poll prctl pread ptrace pwrite quotactl readv recv rt_sigaction rt_sigpending rt_sigprocmask rt_sigtimedwait sched_getparam sched_getscheduler sched_get_priority_max sched_get_priority_min sched_rr_get_interval sched_setparam sched_setscheduler sched_yield select send sendfile setdomainname setgid setfsuid setfsgid setgroups sethostname setitimer setpgid setpriority setregid setresgid setresuid setreuid setrlimit setsid set_thread_area setuid 49 sigaltstack statfs stime sync sysctl sysinfo time times truncate umask umount utime utimes vhangup vm86 waitpid write writev --> The policy file contains two main sections called PERMIT and Reference. Both Java Security Manager and Systrace are concerned with the system call that needs to be permitted and they both deny the rest. Therefore, the judge policy file consists of only those system calls that are permitted for the contest or for a specific problem and not those that are denied. Hence, the permitted system calls need to be mentioned within the <PERMIT> and </PERMIT> tags. For editing the Judge Policy file, a proper syntax needs to be followed. Hence, the judge policy file also contains information for the judges or administrators regarding how to edit. The section called “Reference” just after the </PERMIT> tag explains how to write the system call permissions in the judge policy file. For example, if a judge wants to give a file read permission on “fileread.txt” file, the phrase “fsread fileread.txt” needs to be added in between <FILE> and </FILE> section. Similarly, the time, socket and system related permissions could be added within their respective tags. The Reference section is divided further based on the number of 50 parameters required for making a system call. For example, the phrase “chmod filename mode” represents the “chmod” system call that changes the mode of a given file. To execute this system call, two parameters namely the “filename” and the “mode” are required. Hence, this belongs to “Command + 2 parameters” sub-section. Similarly the rest of the system calls phrases are categorized into their respective sub-sections. The further information regarding these system calls are available in the Linux Man Pages [4]. The “Reference” section and its sub-sections are only for the judges. The code will not read anything after the </PERMIT> tag. In the above judge policy file, permissions are given to “fsread” and “fswrite”. These two system call phrases indicate to the Generate module to create C/C++ and Java policy files that contain permissions to the above-mentioned system calls. The “fsread” system call corresponds to a file read and informs the Generate module to permit file read operation on “fileread.txt” file, in the yet to be generated C/C++ and Java policy files. Similarly, “fswrite” corresponds to file write system call and the Generate module will permit write operation on “filewrite.txt”. In addition, Java can perform certain operations that C/C++ does not support, such as Abstract Window Toolkit (AWT). Hence, permissions to such Java specific operations can be written within <JAVA-ONLY> and </JAVA-ONLY> tags. These tags inform the Generate module that they are Java specific and not to bother for C/C++. The information for the Java specific operations is available in the “Class Security Manager” section of the Oracle’s website [12]. 7.2.3 Generating C/C++ and Java policy files After coming up with contest or problem specific judge policy file, the corresponding C/C++ and Java policy files needs to be created. This is done using the Generate module. “generate” is the 51 binary executable of the Generate module. The following command is used for generating problem specific C/C++ and Java policy files: ./generate judge.policy base.policy <problemletter>.c.policy <problemletter>.java.policy The Generate module takes in contest or problem specific “judge.policy” as the judge policy file and “base.policy” as C/C++ base policy file, as input and produces problem specific C/C++ and Java policy files. The naming conventions are followed while generating these policy files. The word “problemletter” specifies the problem in the contest. Generally it would be A,B,C…. Therefore, for the problem letter ‘A’, the output policy files would be “A.c.policy” and “A.java.policy”. The C/C++ and Java policy files corresponding to the above-mentioned Judge policy file would look like as shown below. C/C++ Systrace Policy File Snippet: linux-fsread: filename eq "fileread.txt" then permit linux-fswrite: filename eq "filewrite.txt" then permit Java Policy File Snippet: grant{ permission java.io.FilePermission "fileread.txt", "read"; permission java.io.FilePermission "filewrite.txt", "write"; }; This completes the necessary changes required to be made on the Sandbox side. Further, PC2 has to be modified to accommodate a command that can invoke the Execute module. 52 7.2.4 Modifying PC2 After generating the output policy files, the way PC2 compiles and executes binary and .class files needs to be edited. For running a Java program, the following changes needs to be made: Program Execution Command Line: run_execute.sh {:basename} java {:problemletter}.java.policy jout.log The “run_execute.sh” script takes .class name, an indicator for Java, input policy file to be used and the output log file name. Subsequently, when a team submission is received by PC2, it executes the submission by invoking the “Program Execution Command Line” which in turn invokes the Execute module. The Execute module generates an output log file which can be referred by judges and administrators to check if there was any security violation. Similar changes are made on the C/C++ compilation and execution side. Program Execution Command Line: run_execute.sh {:basename}.exe c {:problemletter}.c.policy cout.logs 7.3 Executing Team Runs With Sandbox Once the required changes are made in the Sandbox and PC2, the team runs on the Judge’s machine can be made using the Security Sandbox. The judges can opt to execute the participant’s code manually or can go for Auto-Judge option. In both cases, when the execute procedure is invoked, PC2 calls the Execute module through the shell and sends all required inputs. The Execute module runs the C/C++ or Java program based on the input indicator, and generates an output log file that contains information about the security. 53 If there were any security violation, the output of the execution would be incomplete. Further, the corresponding violation would be written into the output log file. If there was no violation then the execution would result in proper output and the output log file contains “No Security Violation” tag. 54 Chapter 8 CONCLUSION This project is implemented on a Linux platform. The Security Sandbox will secure PC2 from those system calls which are prohibited by the policy. The new PC2 tool with Security Sandbox implemented will enhance the current security features. The Security Sandbox is easy to implement and use. It can be easily invoked from PC2 and requires minimal changes in current PC2 system. 8.1 Migration to other major Operating Systems PC2 is implemented using Java and will run on any Java platform including Linux, Windows and Mac Operating systems. However, the Security Sandbox is implemented with Linux in mind and is written mainly using C/C++. This Security Sandbox needs to work on all the platforms where PC2 is present. Therefore, it is necessary to make some fundamental research on how to migrate the Security Sandbox to other operating systems. The Security Sandbox is implemented with two different approaches considering C/C++ and Java. For C/C++, the Security Sandbox uses systrace and for Java, it uses the JVM security manager. Both these features are implemented in the Security Sandbox and it invokes the execution of participant’s code based on a simple indicator supplied by PC2. For Java programs, the JVM takes care of the underlying platform and hence running a Java program will be same for all operating systems. Once a corresponding JVM is installed on the current platform, Java programs can run with no dependencies. Therefore, to run participant’s Java code, no changes are required in the Security Sandbox. 55 For C/C++, the Security Sandbox calls systrace to execute the binary. Currently systrace is available only on UNIX based Operating Systems. Hence for other operating systems, research is needed on what features they provide to implement a Security Sandbox. 8.1.1 Mac OS A version of Systrace is available for Mac OS. Therefore, a small amount of change is required in the current code for the Security Sandbox to work on Mac OS. The Generate module might need to create policy keeping Mac OS in mind. The Execute module simply executes the binary against the policy given by the Generate module. Further, everything runs in a folder. Therefore, the Execute module might not require any changes. 8.1.2 Solaris Since Solaris falls into UNIX OS family, similar changes of Mac OS are required for Solaris too. Therefore, the Security Sandbox can be migrated to Solaris platform with minimal changes. 8.1.3 Windows Windows does not have any such security features that Linux enjoys. There is no systrace or ptrace. Therefore, the entire approach has to be changed when it comes to Windows. However, there is one tool called StraceNT, which is similar to Strace in Linux. Both Strace and StraceNT are passive tracing tools. They simply log information about system calls and other information after executing the binary. By that time, binary executable might caused damage to the system. Therefore, what is needed is an active tracing tool to monitor every system call made by the binary executable at run time. 56 Windows Operating Systems provides a tracing facility called Event Tracing for Windows (ETW). ETW can be used to trace events raised by applications running in user mode and by device drivers running in Kernel mode [18]. Windows also presents a software tracing technology called Windows preprocessor (WPP) which uses ETW. The WPP is used in tracing the operation of a software component [19]. Further research needs to be done on ETW and WPP technologies to see how much they can help in the Security Sandbox. Once Windows develops and incorporates a tool similar to the systrace, then the Security Sandbox can be configured accordingly. The Security Sandbox might need a very new approach to work on Windows. Therefore, current implementation might have to be changed completely. Hence, the Security Sandbox for Windows platform would allow an opportunity for future development. 8.2 Future Development The Security Sandbox is aimed at running C/C++ and Java programs because these are the most commonly used programming languages in the programming contests. In future, the organizers might design a contest that allows other programming and scripting languages such as C#, Perl and Python. Therefore, the current Security Sandbox might need further enhancements to accommodate these languages. Since the Security Sandbox is applied only on the Judge or Administrator’s machine, the participants might take advantage and run malicious code on their machine that may disobey the rules of the contest. During the test run, a participant may try to hack into PC2 software on his or her machine. The Security Sandbox will not monitor these malicious activities. In order to provide security against these types of activities, PC2 system needs to completely encapsulate 57 contest participants so that they would not have access to any machine resources outside the encapsulating system. The new system would provide all the necessary tools including editor, compiler, debugger etc, which are required for the contest. Therefore, the Operating System must start PC2 as soon as it boots. This method might help to reduce or eliminate any malicious activities attempted by the participants on their machine during the contest. Eventually, the Security Sandbox might become one complete security tool for providing a foolproof security and protection for PC2. 58 REFERENCES [1] PC2 Home Page [Online] Available: http://www.ecs.csus.edu/pc2/ [2] ai-contest [Online] Available: http://code.google.com/p/ai-contest/wiki/Sandboxing [3] Marshall Kirk McKusick, Keith Bostic, Michael J. Karels, John Quarterman, “The Design and Implementation of the 4.4 BSD Operating System”, April 1996 [4] Linux Man Pages [Online] Available: http://linuxmanpages.com/ [5] Systrace - Interactive Policy Generation for System Calls [Online] Available: http://www.citi.umich.edu/u/provos/systrace/ [6] Systrace by Neils Provos [Online] Available: http://www.provos.org/index.php?/categories/2-Systrace [7] Hendrik Weimer, “strace Dissecting Programs”, September 19, 2006 [Online] Available: http://www.osreviews.net/reviews/admin/strace [8] Playing with ptrace, Part I [Online] Available: http://www.linuxjournal.com/article/6100 [9] Ray Lai, “Systrace for Slackers”, NYCBUG, March 2006 [Online] Available: http://www.cyth.net/~ray/systrace-talk/ [10] Michael W. Lucas, “Creating Systrace Policies”, February 27, 2003 [Online] Available: http://onlamp.com/pub/a/bsd/2003/02/27/Big_Scary_Daemons.html [11] Ahmad Jalil Qarshi, “How to Call Java Functions from C Using JNI”, January 13, 2008 [Online] Available: http://www.codeproject.com/KB/cpp/CJniJava.aspx 59 [12] Class Security Manager [Online] Available: http://download.oracle.com/javase/6/docs/api/java/lang/SecurityManager.html [13] Miron Sadziak, “Using Java SecurityManager to grant/deny access to system functions”, November 16, 2009 [Online] Available: http://www.javablogging.com/using-java-securitymanager-to-grantdenyaccess-to-system-functions/ [14] JNI Part1: Java Native Interface Introduction and “Hello World” application [Online] Available: http://electrofriends.com/articles/jni/jni-part1-java-native-interface/ [15] Sean R. Owens, “VerySimpleClient.java” [Online] Available: http://darksleep.com/player/SocketExample/VerySimpleClient.java.html [16] Sean R. Owens, “VerySimpleServer.java” [Online] Available: http://www.darksleep.com/player/SocketExample/VerySimpleServer.java.html [17] Sockets Tutorial [Online] Available: http://www.linuxhowtos.org/C_C++/socket.htm [18] Dr. Insung Park and Ricky Buch, “Improve Debugging And Performance Tuning With ETW” [Online] Available: http://msdn.microsoft.com/en-us/magazine/cc163437.aspx [19] WPP Software Tracing, September 07, 2011 [Online] Available: http://msdn.microsoft.com/en-us/library/ff556204.aspx