From 5d1b660e328c334acc8e7920117d08ed992e2d2b Mon Sep 17 00:00:00 2001 From: md_5 Date: Tue, 8 Jul 2014 15:22:26 +1000 Subject: [PATCH] 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. --- .../bungee/api/scheduler/TaskScheduler.java | 19 ++++++ .../main/java/net/md_5/bungee/BungeeCord.java | 2 + .../md_5/bungee/BungeeSecurityManager.java | 58 +++++++++++++++++++ .../bungee/scheduler/BungeeScheduler.java | 16 +++++ 4 files changed, 95 insertions(+) create mode 100644 proxy/src/main/java/net/md_5/bungee/BungeeSecurityManager.java diff --git a/api/src/main/java/net/md_5/bungee/api/scheduler/TaskScheduler.java b/api/src/main/java/net/md_5/bungee/api/scheduler/TaskScheduler.java index d4cfe8a7..359c3632 100644 --- a/api/src/main/java/net/md_5/bungee/api/scheduler/TaskScheduler.java +++ b/api/src/main/java/net/md_5/bungee/api/scheduler/TaskScheduler.java @@ -1,5 +1,6 @@ package net.md_5.bungee.api.scheduler; +import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import net.md_5.bungee.api.plugin.Plugin; @@ -71,4 +72,22 @@ public interface TaskScheduler * @return the scheduled task */ 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(); + } } diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java index e523590e..638d9111 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java @@ -159,6 +159,8 @@ public class BungeeCord extends ProxyServer public BungeeCord() throws IOException { + System.setSecurityManager( new BungeeSecurityManager() ); + try { bundle = ResourceBundle.getBundle( "messages" ); diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeSecurityManager.java b/proxy/src/main/java/net/md_5/bungee/BungeeSecurityManager.java new file mode 100644 index 00000000..f169eabb --- /dev/null +++ b/proxy/src/main/java/net/md_5/bungee/BungeeSecurityManager.java @@ -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) + { + } +} diff --git a/proxy/src/main/java/net/md_5/bungee/scheduler/BungeeScheduler.java b/proxy/src/main/java/net/md_5/bungee/scheduler/BungeeScheduler.java index 53048d2d..06568a90 100644 --- a/proxy/src/main/java/net/md_5/bungee/scheduler/BungeeScheduler.java +++ b/proxy/src/main/java/net/md_5/bungee/scheduler/BungeeScheduler.java @@ -25,6 +25,16 @@ public class BungeeScheduler implements TaskScheduler private final AtomicInteger taskCounter = new AtomicInteger(); private final TIntObjectMap tasks = TCollections.synchronizedMap( new TIntObjectHashMap() ); private final Multimap tasksByPlugin = Multimaps.synchronizedMultimap( HashMultimap.create() ); + // + private final Unsafe unsafe = new Unsafe() + { + + @Override + public ExecutorService getExecutorService() + { + return s; + } + }; public void shutdown() { @@ -82,4 +92,10 @@ public class BungeeScheduler implements TaskScheduler s.execute( prepared ); return prepared; } + + @Override + public Unsafe unsafe() + { + return unsafe; + } }