Recently in the study of Linux-based OJ systems, and then want to write a series of their own articles to record their learning results this time.
First of all, from the principle, OJ function implementation is not difficult, the most important solution is the security problem. To summarize, the security aspect is primarily that the user may submit malicious and unfriendly code. On how to filter these unsafe code, I collected a lot of information from the Internet, the general idea is as follows:
Say the wrong thing first:
1. All string filtering is not by some numbers, deceptive pits themselves, C language powerful macro almost no string filtering, and the injury is very common, for example, if you are in the program accidentally defined a variable called fork, then your program can not expect AC, Because string filtering will think of your fork as the fork that created the subprocess, which is not allowed.
2. Manual audit of the header file, remove some of the header files or comments Off part is hard and useless; After doing such a job you almost no longer want to upgrade the compiler and the header file, the more frightening is that the work requires you to language, compiler, connectors have a certain degree of understanding, And I think people with enough knowledge will understand that there is no reason to do this: even without a header file, without a function prototype, the method of invoking the system calls is a lot, and it is not very troublesome.
Besides, the preparatory work:
1. Familiarize yourself with your target system (Windows or Linux): It is important to understand how the native system invocation API is used (or how you block it), and it is best to understand the assembly level. It is necessary to understand the user system, privilege control and resource limitation under this platform. It's best to know about process tracking, debugging, monitoring tools, or system calls, such as Ptrace under Linux. It is a good idea to understand the various sandbox throttling features provided by the target system.
2. Understand your programming language and toolchain: It is important to understand the characteristics of your target language and its rules and limitations in general OI/ACM competitions. It is important to understand the functionality of your toolchain and the various parameters.
3. Have enough programming skills, for such a small program, should strictly eliminate buffer overflow and other bugs.
Finally, my approach: My target platform is Linux, the target language is C/c++,java,python.
1. Operating system level:
A. Limitations on time resources.
Memory: I use the rlimit to control, but also is convenient at the end of the run after the memory usage of data, but one drawback is that if you declare a large space but never visited will not be counted in, but observed that many ACM or OI contests are also handled this way, All this is not a problem.
Time: The first is also used Rlimit CPU time control, note that it can only control CPU time, can not control the actual running time, so like sleep or IO blocking the situation is no way, so there is an additional alarm added to the actual restrictions. Depending on the management of most competitions, the final statistic time is CPU time.
File handle: Also can be implemented by Rlimit, to ensure that the program does not open too many files. However, in fact, the file this piece of the problem is more, if feasible, it is best to use stdio and then pipeline redirection, completely prohibit the program's file IO operation.
B. Access control:
Restrict programs to run in the specified directory with low-privileged user nobody. Because it is a race program, the use of the dynamic link library is very limited, so the direct static compilation, so that the running directory is not required to connect. So.
Make the necessary permissions control, such as to set the input file and program file itself to the program's running user is read-only and not writable.
C. Permission control:
The monitoring program runs with root privileges, completes the necessary preparation and then fork and switches to the restricted user (such as nobody) to run the program.
Rlimit settings are hard limit, non-root cannot be modified.
After the user is set up correctly, nobody restricted users cannot escape.
D. System call Control:
The above (especially the first step) is a big problem, and even if it's not root, it can do a lot of things. And do not say fork or the like, just the alarm, you can easily put the timer canceled or simply take the initiative to receive this signal. So the fundamental thing is to use a debugger like Ptrace to attach the program, monitor all system calls, and whitelist + counter (such as exec and open) filtering. This step is actually the most troublesome (different platform system call number is not the same, we use the Strace project in the order of the call number).
E. Further:
If you're more familiar with the operating system, there are some more interesting things to do. For example, the Seccomp feature under Linux (Seccomp-wikipedia, the Chrome Linux version is used in the sandbox), especially after the late addition of SECCOMP-BPF to become more user-friendly. Also such as SELinux can be used as a link of defend-by-depth. In addition, Cgroup can also be used in fact.
2. Compile level:
A. Many compiler tools provide powerful parameter control that allows you to include actions such as disabling inline ASM, restricting connection paths, and so on. It will certainly help to read through the manpage.
B. Algorithmic contests are recommended for static compilation, which makes it much easier to control the dynamic link library.
C. Be careful of some "advanced features" during compilation, such as C's include in fact there are many clever usage, try to #include "/dev/random" under Linux or #include "/dev/tty" and the like (these two things will be the network of a lot of two Stream OJ directly to die ... )。
D. Do not compile with the root user, the more complex the program is more prone to bugs, in case one day out of a compiler 0day ...
E. Consider the same time and resource limitations for the compilation process as additional protection.
3. Architectural Level:
A. Running in a virtual machine/container
B. Snapshots
C. Heartbeat detection
Design and development of OJ system based on Linux (I.)