/*******************************************************************************
* Copyright (c) 2001, 2010 Mathew A. Nelson and Robocode contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://robocode.sourceforge.net/license/epl-v10.html
*
* Contributors:
* Mathew A. Nelson
* - Initial API and implementation
* Flemming N. Larsen
* - Code cleanup
* - Added checkPackageAccess() to limit access to the robocode.util Robocode
* package only
* - Ported to Java 5.0
* - Removed unnecessary method synchronization
* - Fixed potential NullPointerException in getFileOutputStream()
* - Added setStatus()
* - Fixed synchronization issue with accessing battleThread
* Robert D. Maupin
* - Replaced old collection types like Vector and Hashtable with
* synchronized List and HashMap
* Pavel Savara
* - Re-work of robot interfaces
* - we create safe AWT queue for robot's thread group
* - moved most of checks to RobocodeSecurityPolicy
*******************************************************************************/
package net.sf.robocode.host.security;
import net.sf.robocode.host.IHostedThread;
import net.sf.robocode.host.IThreadManager;
import java.security.AccessControlException;
/**
* @author Mathew A. Nelson (original)
* @author Flemming N. Larsen (contributor)
* @author Robert D. Maupin (contributor)
* @author Pavel Savara (contributor)
*/
public class RobocodeSecurityManager extends SecurityManager {
public static final boolean isSecutityOn = !System.getProperty("NOSECURITY", "false").equals("true");
private final IThreadManager threadManager;
public RobocodeSecurityManager(IThreadManager threadManager) {
super();
this.threadManager = threadManager;
ThreadGroup tg = Thread.currentThread().getThreadGroup();
while (tg != null) {
threadManager.addSafeThreadGroup(tg);
tg = tg.getParent();
}
// We need to exercise it in order to load all used classes on this thread
isSafeThread(Thread.currentThread());
if (isSecutityOn) {
System.setSecurityManager(this);
}
}
@Override
public void checkAccess(Thread t) {
if (!isSecutityOn) {
return;
}
Thread c = Thread.currentThread();
if (isSafeThread(c)) {
return;
}
super.checkAccess(t);
// Threads belonging to other thread groups is not allowed to access threads belonging to other thread groups
// Bug fix [3021140] Possible for robot to kill other robot threads.
// In the following the thread group of the current thread must be in the thread group hierarchy of the
// attacker thread; otherwise an AccessControlException must be thrown.
boolean found = false;
ThreadGroup cg = c.getThreadGroup();
ThreadGroup tg = t.getThreadGroup();
while (tg != null) {
if (tg == cg) {
found = true;
break;
}
try {
tg = tg.getParent();
} catch (AccessControlException e) {
// We expect an AccessControlException due to missing RuntimePermission modifyThreadGroup
break;
}
}
if (!found) {
String message = "Preventing " + c.getName() + " from access to " + t.getName();
IHostedThread robotProxy = threadManager.getLoadedOrLoadingRobotProxy(c);
if (robotProxy != null) {
robotProxy.punishSecurityViolation(message);
}
throw new AccessControlException(message);
}
}
@Override
public void checkAccess(ThreadGroup g) {
if (!isSecutityOn) {
return;
}
Thread c = Thread.currentThread();
if (isSafeThread(c)) {
return;
}
super.checkAccess(g);
final ThreadGroup cg = c.getThreadGroup();
if (cg == null) {
// What the heck is going on here? JDK 1.3 is sending me a dead thread.
// This crashes the entire jvm if I don't return here.
return;
}
IHostedThread robotProxy = threadManager.getLoadedOrLoadingRobotProxy(c);
if (robotProxy == null) {
throw new AccessControlException("Preventing " + c.getName() + " from access to " + g.getName());
}
if (cg.activeCount() > 5) {
String message = "Robots are only allowed to create up to 5 threads!";
robotProxy.punishSecurityViolation(message);
throw new AccessControlException(message);
}
}
private boolean isSafeThread(Thread c) {
return threadManager.isSafeThread(c);
}
}