Isolation / cheat prevention of third party code (multiplayer)

Introduction
I am writing a 2D soccer game which is kind of multiplayer. It is special in the way that players are driven by third party software. In short: Someone implements the given interface for controlling a soccer player, plugs his player implementation into the game engine together with the implementation of someone else’s player implementation and both implementations will play a soccer match against each other. This is similar (but simpler) to RoboCup’s Simulations Leage (http://www.robocup.org/robocup-soccer/simulation/, http://www.youtube.com/watch?v=BVWkndHk3AE) or MIT’s Battlecode (http://www.battlecode.org/) competition. The game is written in scala with use the akka (akka.io) actors.

I will copy parts of this introduction to other questions refering to this game as necessary.

Architecture overview

  • There are model classes like Ball, Body (of the players), SoccerField, Goal etc.
  • There is an interface which must be implemented by each player implementation.
  • There is a central class MatchController which controlls the game process like state and cycles.
  • Between the player implementations and the MatchController there are intermediate actors handling the communication between the players and the MatchController by message passing. The players can only see a limited interface implemted by these actors. The communication is transparent to the players. The players don’t know anything about the MatchController. They event don’t know that it exists. The only thing that the players know about is the limited interface provided by the intermediate actors.
  • The MatchController is partially responsible for cheat prevention as it must validate incoming messages. For example it must handle the case that a player tries to exeed maximum movement speed.

The isolation problem
Currently the player implementations are executed in the same process together with the MatchController. I assume that there are possibilities for player implementations to cheat or manipulate the game for example through use of reflection / meta programming.

In the middle or long term, I would like to isolate the player implementations from each other and the MatchController. Ideally even players of the same team and with the same implementation would be isolated from each other.

Which options do I have to get such isolation?
What are the advantages and disadvantages of these options?

Here are the ideas that came to my mind:

  • Each player in a separate operating system process. This looks most promising, because it is a well known and established way of isolation. Maybe this will consume much memory and swap space, at least this happens when I use Chromium on my Linux system (compared to Firefox), but this is a little bit speculative from my perspective. Memory consumption may be limited by JVM settings.
  • There is something like a Java Isolation API. Don’t know much about it, but may reduce memory consumption.
  • Sandbox / Security Manager / Security Policy. Don’t know if it is possible to create proper isolation of different parts of a Java program. Might be combined with the OS process aproach to prevent the player processes to perform disallowed actions. If I think of an unlikely but really evil player implementation it might e.g. discover the oponent’s player processes and stop them. There where some vulnerabilities permitting a Java program easily bypass the Security Manager and break out of the sandbox, last year. I don’t know if they are all fixed now.
  • I think there a couple of other aproaches trying to create isolation on the Java platform partially by modifiing the JVM’s architecture, but I don’t know if there are any of them at a usable state of progress in implementation and standardization.
  • JCSP. Don’t know much about it, yet. http://www.cs.kent.ac.uk/projects/ofa/jcsp/, http://www.java-gaming.org/topics/jcsp-lw-isolated-processes-threads-in-java/2711/view.html

Do you have any more options or some hints or comments on isolation?

Thanks in advance.

maybe you could do it with multiple classloaders.
You start up your main App with the hole game simulation, controllers and so on. And then create an own classloader for each player, which does only have classpath access to some interface classes.

Thats just a wild guess I would probably investigate a bit if I would want to do something similar.

On the other hand, can’t you disallow reflection and so on when a security manager is set?

Thx, for your answer. Yes, I have heard of this. Could be a usable isolation in the first place, but I would like to know, if there is really impossible to find all the objects loaded by other classloaders. For example, Eclipse’s debugger can do “heap walking” and find all instances of a type. I don’t if that is limited to a classloader.

Anyway I don’t think that anyone implementing a player will go so far, so this is a bit academic on that level, but I would like to know how far I can go.

Yes, I think the default SecurityManager / policy (at least partially) prevents usage of reflection, but what if some part of the game uses or must use reflection? I don’t know yet, if I can write a policy so that some part of the program is allowed to use reflection while another part can not do so.

As far as I remember e.g. there where some problems with Apache Tomcat when activating the SecurityManager. Persistence frameworks, don’t they frequently use reflection? Just examples where IMHO you can shoot yourself into the foot, when disabling reflection completely, but I don’t know all that exactly.

To make it clear: I did not use reflection myself in the program. Possibly there is some reflection going on under the hood (e.g. by akka), but I don’t think so. Also I don’t make use of a persistence framework,yet. So again, this is a bit academic, but beyond finding a practical solution for implementation I would like to understand.

So I am a slave for my passion and I am forced to years of research again. :point: :yawn: :o ::slight_smile: :persecutioncomplex: 8)

Run in seperate processes… seriously.

There is no other way to defend your game-process from hostile code, even if it just causes an OOME:


List<byte[]> evil = new ArrayList<>();
while(true) {
   evil.add(new byte[1024]);
}

The more I think about it, the more I am convinced, that you are right. This would be fun, too:


if(isFebruaryThe29th()) {
    System.exit(0);
}

Put this somewhere in an enterprise application. ;D

OK, I will implement it to use separate processes, but will still have to think about what I want to allow and disallow these processes to do and maybe additionally use a SecurityManager to limit the processes’s capabilities.

The other approaches might be interesting, too, but for third party code, this seems the best.

Sure, by using seperate processes you’re far from done. You don’t want the process to have access to the HDD, nor allow it to do any networking beyond accessing the ‘parent process’ (only allow connectivity on, say, 127.0.0.1:6582)

Further, you want it to limit Thread priorities:


Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
Thread.currentThread().getThreadGroup().setPriority(Thread.MIN_PRIORITY);
// all new threads spawned cannot have a priority over MIN_PRIORITY

It’s not that easy, because you can’t just prevent all disk I/O, because then you cannot load ‘net.dll’ from the JRE (which enables networking). So you have to do some dummy network I/O prior to setting the security manager, so that all required native libraries are loaded - and only then lock it down.


new Socket("127.0.0.1", 6582).close();
System.setSecurityManager(new VeryFancySecurityManager())

I hoped that akka makes the networking cheap, but don’t know how it will react on a SecurityManager. I will see. This will be some work and I hope some fun, too. ^^