tags:

views:

386

answers:

3

It started with this question, followed up with this question and now led to the present one. :)

The task is as follows: make a Windows program that will run another program in a limited environment. The other program cannot be trusted, so it has to be ready for hackish code. More specifically:

  • Limit the available memory to some X MB (given as a parameter);
  • Limit the available execution time to some X milliseconds (given as a parameter). Note, that this is the Kernel Time + User Time, but not Idle time. On the other hand, Idle time also has to be limited so that the program cannot Sleep() infinitely.
  • Upon program's termination report the CPU time it actually spent, as precisely as possible. Milliseconds would be good, centiseconds acceptable, less than that would not be nice. CPU cycles would be ideal.
  • If the program crashes, report some information about the crash (the more the better, but don't go overboard with stack traces and the like).
  • Preferably capture all the output of the program and report that too;
  • The program is supposed to be using just the current directory, plus maybe some mandatory .DLLs from SYSTEM32 (like kernel.dll, user32.dll, etc.). Limit access to anything else as much as possible. Accessing things like registry and network should not be needed (unless the mandatory .DLL's require it). The less access, the better.

This will be needed for a computing olympiad support software. This program will run the participants submissions on the central server, so you can expect pretty much anything there. Crashes will be routine, and some hacking attempts can be expected too.

So - how would you go about making such a program? What would you use? In the previous topics (see above) it has become clear that attaching as a debugger is a bad idea, although perhaps I'm simply too clumsy.

A: 

Virtualization solutions solve this problem. Maybe you can base your solution on VMWare (or equivalent) and launch separate virtual machines (one per process). You'll get good isolation, control over memory/cpu usage and reports. There's the overhead of the wrapping OS per process, but it depending on your project's requirements it might be acceptable.

Assaf Lavie
Virtualization would be nice, but I'm not sure how to use it in this scenario. First of all, there will be many submissions, so testing should be as short as possible. Most test runs will be limited to ~1 second per test case, and there will be around 10 test cases.
Vilx-
Also, if I start a whole virtual machine (or even bring it out of sleep), I still must place the restrictions/measurements on just the one process in it, not the whole VM. Essentially we're back at step one.
Vilx-
Also note, that the measurements have to be quite precise. Milliseconds would be preferable, centiseconds would be acceptable. Deciseconds would be crappy. Come to think of it, CPU _cycles_ would be the best. :P
Vilx-
Sounds heavy handed
Mo Flanagan
What do you mean?
Vilx-
The VM is going to help with quotas and not much else. And you still have to write the code to restrict the process within the VM. Plus now you get to load a GB+ for each process due to the OS image.
Mo Flanagan
My thoughts exactly.
Vilx-
+4  A: 

You are pretty much building the same process model as IIS - fun! I would use the same tools that IIS uses, its relatively robust against hacking and its designed to partition your system up into many concurrent jobs.

You can use Win32 Jobs to set quotas for memory, cpu, threads and you can set up a security context for different processes to run in, thus limiting access to the file system.

For monitoring, I would look at WMI.

For stack trace when hanging or crashing, I have used ADPlus again from Microsoft.

For capturing console output, check out Creating a Child Process with Redirected Input Output.

Regarding security restrictions, create a low privilege user account and run the job / process as that user.

Mo Flanagan
Yup, that I know of. Except for the Idle time, but I suppose I could monitor that as well. Do you have any ideas about the rest?
Vilx-
Jobs solves part of the problem. But malicious code could still go wild in a Job.
Assaf Lavie
Limiting security context is also nice, that's what I've been trying to use too. Although I have to admit - with little success. Somehow I cannot find the right ACL to use. Would a sample be much to ask?
Vilx-
I don't need stack trace IMHO. The programs will be compiled with all optimizations anyway. But it would be nice to see if it was StackOverflow, GPF, or something else.
Vilx-
I would just create a low privilege user and run the process as that. The program can screw up the registry, but only the HKCU keys for the user.
Mo Flanagan
As for the Windows User suggestion - I'm not sure it's a good idea. The program could probably access some user folders and data, and do something hackish there. Like copy itself in the startup folder or something.
Vilx-
Keep in mind - EVERY process runs as a Windows User, its purely a matter of which user. Either it will be the user which launched the process (probably not what you want) or a user of your creating. There is no such thing as running a process as a non-user.
Mo Flanagan
There is such a thing as a restricted token. The process will still run as a user, but not with all the rights that the user posesses. I can make it run with a subset of my choosing. The problem is just that I don't know what to choose there. The choices are many. :)
Vilx-
So your talking the Se* flags, things like that? Take a look at the properties of one of the restricted system accounts like Guest or IUSR_ComputerName, maybe they could provide a model.
Mo Flanagan
A: 
  • Limit the available memory to some X MB (given as a parameter); Use VMWare or similar virtual enviroments
  • Limit the available execution time to some X milliseconds (given as a parameter). Note, that this is the Kernel Time + User Time, but not Idle time. On the other hand, Idle time also has to be limited so that the program cannot Sleep() infinitely.
  • Upon program's termination report the CPU time it actually spent; Build in program's code. (Hook on CPU power
  • If the program crashes, report some information about the crash (the more the better, but don't go overboard with stack traces and the like). Build in program's code. (Exception handling)
  • Preferably capture all the output of the program and report that too; Build in program's code (Logfile).
  • The program is supposed to be using just the current directory, plus maybe some mandatory .DLLs from SYSTEM32 (like kernel.dll,user32.dll, etc.). Limit access to anything else as much as possible. Accessing things like registry and network should not be needed (unless the mandatory .DLL's require it). The less access, the better. Build in program's code. (If your program won't use register it won't use it.
PoweRoy
I don't want to modify users submissions. People here are told what compiler with what options will be used, and they depend on that. Injecting my own code can (and probably will) create unexpected side-effects.
Vilx-