Inquiry / Request for feedback [Service: a sandboxed JVM on a public server]

Hm… yeah, I discovered ‘atoi’ after writing that parseInt method, and I kinda didn’t want to throw my code away :-*

About ‘const correctness’, would it be harmful if I do not change my code? I don’t want to build much else in C, and spending a few hours grasping all ins-and-outs of const, seems like a waste to me…? Thanks for your observation though, but it isn’t obvious to me what should be changed, and how it improves the program. Sorry for my ignorance :-[

I (am pretty sure I) can trust you, and I do, as you currently run your programs without a SecurityManager.

You have to realize though, that enabling reflection allows you to access to sun.misc.Unsafe, nullifying the memory-location of the SecurityManager with a few tricks, or you can pretty much take over the entire OS from there. There is stuff running on that server that I don’t want to lose :slight_smile:

I certainly don’t want to limit the people that I trust, and I might want to make reflection and option, but it will certainly not be available for anybody (paying for and) using this service.

Update: as it turns out, you can use Reflection, as long as you do not use {field|method}.setAccessible(true); :wink:

If it already works and you’re not going to extend it then there’s not much point going back and adding const correctness. But just for reference here’s what I’d tweek:


void msleep(const int x) // don't want to accidentally change your in param
{
    struct timespec sleeptime;
    struct timespec remaining;
    int result;               
    remaining.tv_sec = x/1000;
    remaining.tv_nsec = (x%1000)*1000000;
    do {                                 
        sleeptime.tv_sec = remaining.tv_sec;
        sleeptime.tv_nsec = remaining.tv_nsec;
        result = nanosleep(&sleeptime,&remaining);
    } while(0>result && EINTR==errno);
}



int parseInt(const char* const arg) // both pointer is const and pointed-to data is const
{
   int num = 0;
   while(*arg)
      num = (num*10)+((*arg++)-'0');
   return num;
}



int main(int argc, char* argv[])
{
   if(argc != 4)
   {
      printf("Usage: {PID} {INTERVAL} {PERCENTAGE}\n");
      return 1;
   }

   const int pid  = parseInt(argv[1]);
   const int intr = parseInt(argv[2]);
   const int p100 = parseInt(argv[3]);

   const int work = intr * p100 / 100;
   const int wait = intr - work;

   while(1)
   {
      if(kill(pid, SIGSTOP)!=0)break;
      msleep(wait);
      if(kill(pid, SIGCONT)!=0)break;
      msleep(work);
   }
}

Since you’re only using straight C here with no classes, use of const is nice and simple, basically like ‘final’ in Java for primatives.

Thanks, will make the changes as it turns out it’s not much magic. I didn’t realize that I was passing pointers, instead of a copy of the pointer, like in Java (or a copy of the value at the pointer, for primitives, that is).

I wonder have you looked at http://www.jcp.org/en/jsr/detail?id=121

Runtime.exec() creates a heavyweight process everytime, you could have also started a bash and issue it commands, JNI works too offcourse.

JCP121 looks like what I need, but I don’t really want to wait a few years, when I can code something ‘like’ it in a few days.

You’re right about the overhead of Runtime.exec, yet invoking bash, and sending “kill -CONT 7563” to it, creates a new ‘kill’ process too, so the overhead would still be there. To implement this in JNI is an interesting thought though, and I might give it a try.

Have not really looked a lot into this, but I think that MyJavaServer http://www.myjavaserver.com/ give you a lot of access and even a DB completely for free, if you just want to do some tests. You just have to pass a simple test to prove that you are worthy :), should be no problem. 5MB of disk space, but don´t know how much CPU power and mem you will get. I signed up a long time ago, but haven´t really used it yet…

from URL: http://www.myjavaserver.com/exec/rsa1/.eMDHP2xXfMz94wAH1MjHvMCHnNCLjwBL1wp0f2y

Hm… way too much J2EE oriented for a game-server eh?

With only 25 lines of stdout you can forget remote debugging. The more info the better, especially when events occur hours from eachother.

It’s a nice service but with 5MB of harddisk you are pretty limited, and I can add a MySQL database too… I guess :slight_smile:

At the moment it is almost up and running. At least it works fine locally (which shouldn’t be any different from running at my server)

I’m now building a UI client to transfer files to/from the server and monitor the stdout/stderr in realtime.

Client source


package myapp;

import craterstudio.apps.sandbox.SandboxStats;


public class Main
{
	private static SandboxStats stats;

	public static void sandbox(SandboxStats stats)
	{
		Main.stats = stats;
	}

	public static void main(String[] args)
	{
		// your app here
	}
}

Example app using sandbox-statistics


	public static void main(String[] args) throws Exception
	{
		for(int i=0; i<10; i++)
		{
			int secondsInterval = 3;
			String avg = String.valueOf(stats.getAverageCpuUsage(secondsInterval));
			if(avg.length() > 5) avg = avg.substring(0,5);

			System.out.println();
			System.out.println("Main.main(uptime:        "+stats.getUptime()+"ms)");
			System.out.println("Main.main(cpu-time:      "+stats.getTotalCpuTime()+"ms)");
			System.out.println("Main.main(avg. cpu-time: "+avg+"/1.000) over "+secondsInterval+" seconds");

			for(int k=0; k<65536; k++)
				for(int m=0; m<1024; m++)
					Math.sqrt(k*m);

			Thread.sleep(1000);
		}

		System.exit(0); // optional
	}

Output


Main.main(uptime:        1140ms)
Main.main(cpu-time:      93ms)
Main.main(avg. cpu-time: 0.031/1.000) over 3 seconds

Main.main(uptime:        2237ms)
Main.main(cpu-time:      202ms)
Main.main(avg. cpu-time: 0.067/1.000) over 3 seconds

Main.main(uptime:        3322ms)
Main.main(cpu-time:      296ms)
Main.main(avg. cpu-time: 0.098/1.000) over 3 seconds

Main.main(uptime:        4407ms)
Main.main(cpu-time:      374ms)
Main.main(avg. cpu-time: 0.093/1.000) over 3 seconds

I have found a way to determine heap-usage per sandbox in the JVM (heapdump analysis), so I can now let a lot of users share the same JVM to significantly reduce the overhead - while still ensuring everybody gets their own guaranteed heapspace. So now a 64MB share will really be 64MB, without a ~8MB of JVM footprint.

Further, I think I won’t have a nice desktop-app to connect to the sandbox - people just have to connect to some port on the server (with a user/pass) and fetch the stdout/stderr/stdin streams from there. FTP will be used for transfering files. For people doing networked games a GUI will probably just get in the way…

I’m extremely busy, and today was the first time I worked on this service, since my latest post in this thread… :-\

That’s fantastic. If you make a simple server demo that runs a jar and gets the std out/in then people should find it pretty easy to use the service.

If you can easily relax the no-reflection security aspect then I’d like to use this with my app. 8)

What are you busy with these days anyway? I assume it’s work, are you doing Swing, NIO, or what?!

Keith

Quite a few posts earlier, I posted that Reflection was supported, at long as you do not use {field|method}.setAccessible(true). I assume that is enough… right? I can’t even block ‘safe’ use of Reflection, even if I’d want to :slight_smile:

I'm busy with building a large website, with an Applet to build/modify closets in detail, with my own isometric software renderer - it's a webshop in Spain (and I don't speak a word Spanish), and it's about to launch April 4th. *shiver*. The design, development (tens of thousands lines of Javascript - not to mention PHP - aaaaah!!), content management system, ordering stuff, ecommerce-handling is all done by me, and there is a lot at stake - so I'm pretty much working all day on it - that includes nights!

And after April 4th it will be maintainance and support and whatnot - but fortunately no strict deadlines. :slight_smile:

Anyway, I bet I can get a demo server up and running in a few hours. Maybe tomorrow

Yes, I remember, I should have said that I needed {field|method}.setAccessible(true) to be allowed. :stuck_out_tongue:

Sounds like a cool project. Even though it’s big, at least you’ve got control over the whole thing from start to finish.

By allowing all reflection, the isolation/sandbox securitymanager can just as well be not there at all.

Just a tiny example:


Field field = System.class.getDeclaredField("security");
field.setAccessible(true);
field.set(null);

Tadaaaa, the SecurityManager is uninstalled. :-*

The ReflectPermission does not give any info about what field/method is accessed :frowning:
It’s like that NetPermission that doesn’t tell me the host the ServerSocket wants to bind to… it’s always “localhost”, bleh

Why? (out of interest)