Implement Security Manager

This commit adds the basis for the intergration of a security manager into BungeeCord. The goal of the security manager is to prevent plugins from doing potentially dangerous or otherwise undesirable behaviour that may damage the stability of Bungee itself or pose a risk to the user's server.

One common theme in some Bungee plugins, especially those which were written in the very early days, is using Threads and ExecutorServices for scheduling purposes. Not only is this inefficient as there is no use of the thread caching features provided by the scheduler, it is also difficult to track who created which thread. Additionally creating threads not managed by the BungeeCord scheduler poses issues for when|if a plugin reload system is implemented, as these threads cannot be appropriately cleaned up and may continue to leak class references or perhaps even continue executing.

At this stage the SecurityManager is set to warn of prohibited actions, but not block them. For some plugins using external APIs, where usage of an ExecutorService is unavoidable, we have included an Unsafe interface to the scheduler which allows direct access to the underlying ExecutorService, or potentially a compatability wrapper.
This commit is contained in:
md_5 2014-07-08 15:22:26 +10:00
parent 7347daf203
commit 5d1b660e32
4 changed files with 95 additions and 0 deletions

View File

@ -1,5 +1,6 @@
package net.md_5.bungee.api.scheduler; package net.md_5.bungee.api.scheduler;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.plugin.Plugin;
@ -71,4 +72,22 @@ public interface TaskScheduler
* @return the scheduled task * @return the scheduled task
*/ */
ScheduledTask schedule(Plugin owner, Runnable task, long delay, long period, TimeUnit unit); ScheduledTask schedule(Plugin owner, Runnable task, long delay, long period, TimeUnit unit);
/**
* Get the unsafe methods of this class.
*
* @return the unsafe method interface
*/
Unsafe unsafe();
interface Unsafe
{
/**
* An executor service which underlies this scheduler.
*
* @return the underlying executor service or compatible wrapper
*/
ExecutorService getExecutorService();
}
} }

View File

@ -159,6 +159,8 @@ public class BungeeCord extends ProxyServer
public BungeeCord() throws IOException public BungeeCord() throws IOException
{ {
System.setSecurityManager( new BungeeSecurityManager() );
try try
{ {
bundle = ResourceBundle.getBundle( "messages" ); bundle = ResourceBundle.getBundle( "messages" );

View File

@ -0,0 +1,58 @@
package net.md_5.bungee;
import java.security.AccessControlException;
import java.security.Permission;
import java.util.logging.Level;
import net.md_5.bungee.api.ProxyServer;
public class BungeeSecurityManager extends SecurityManager
{
private static final boolean ENFORCE = false;
private void checkRestricted(String text)
{
Class[] context = getClassContext();
for ( int i = 2; i < context.length; i++ )
{
ClassLoader loader = context[i].getClassLoader();
// Bungee can do everything
if ( loader == ClassLoader.getSystemClassLoader() )
{
break;
}
// Everyone but system can't do anything
if ( loader != null )
{
AccessControlException ex = new AccessControlException( "Plugin violation: " + text );
if ( ENFORCE )
{
throw ex;
}
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Plugin performed restricted action, please inform them to use proper API methods: " + text, ex );
break;
}
}
}
@Override
public void checkExit(int status)
{
checkRestricted( "Exit: Cannot close VM" );
}
@Override
public ThreadGroup getThreadGroup()
{
checkRestricted( "Thread Creation: Use scheduler" );
return super.getThreadGroup();
}
@Override
public void checkPermission(Permission perm)
{
}
}

View File

@ -25,6 +25,16 @@ public class BungeeScheduler implements TaskScheduler
private final AtomicInteger taskCounter = new AtomicInteger(); private final AtomicInteger taskCounter = new AtomicInteger();
private final TIntObjectMap<BungeeTask> tasks = TCollections.synchronizedMap( new TIntObjectHashMap<BungeeTask>() ); private final TIntObjectMap<BungeeTask> tasks = TCollections.synchronizedMap( new TIntObjectHashMap<BungeeTask>() );
private final Multimap<Plugin, BungeeTask> tasksByPlugin = Multimaps.synchronizedMultimap( HashMultimap.<Plugin, BungeeTask>create() ); private final Multimap<Plugin, BungeeTask> tasksByPlugin = Multimaps.synchronizedMultimap( HashMultimap.<Plugin, BungeeTask>create() );
//
private final Unsafe unsafe = new Unsafe()
{
@Override
public ExecutorService getExecutorService()
{
return s;
}
};
public void shutdown() public void shutdown()
{ {
@ -82,4 +92,10 @@ public class BungeeScheduler implements TaskScheduler
s.execute( prepared ); s.execute( prepared );
return prepared; return prepared;
} }
@Override
public Unsafe unsafe()
{
return unsafe;
}
} }