Do not allow plugins to make multiple instances of their main class.

Prevents foot shooting, eg #2772
This commit is contained in:
md_5 2020-02-20 12:24:01 +11:00
parent e6b0d43d66
commit f41b1fc821
4 changed files with 54 additions and 14 deletions

View File

@ -1,5 +1,6 @@
package net.md_5.bungee.api.plugin;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.io.File;
import java.io.InputStream;
@ -27,6 +28,22 @@ public class Plugin
@Getter
private Logger logger;
public Plugin()
{
ClassLoader classLoader = getClass().getClassLoader();
Preconditions.checkState( classLoader instanceof PluginClassloader, "Plugin requires " + PluginClassloader.class.getName() );
( (PluginClassloader) classLoader ).init( this );
}
protected Plugin(ProxyServer proxy, PluginDescription description)
{
ClassLoader classLoader = getClass().getClassLoader();
Preconditions.checkState( !( classLoader instanceof PluginClassloader ), "Cannot use initialization constructor at runtime" );
// init( proxy, description );
}
/**
* Called when the plugin has just been loaded. Most of the proxy will not
* be initialized, so only use it for registering

View File

@ -1,37 +1,47 @@
package net.md_5.bungee.api.plugin;
import com.google.common.base.Preconditions;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import net.md_5.bungee.api.ProxyServer;
public class PluginClassloader extends URLClassLoader
final class PluginClassloader extends URLClassLoader
{
private static final Set<PluginClassloader> allLoaders = new CopyOnWriteArraySet<>();
//
private final ProxyServer proxy;
private final PluginDescription desc;
//
private Plugin plugin;
static
{
ClassLoader.registerAsParallelCapable();
}
public PluginClassloader(URL[] urls)
public PluginClassloader(ProxyServer proxy, PluginDescription desc, URL[] urls)
{
super( urls );
this.proxy = proxy;
this.desc = desc;
allLoaders.add( this );
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
protected Class<?> findClass(String name) throws ClassNotFoundException
{
return loadClass0( name, resolve, true );
return findClass0( name, true );
}
private Class<?> loadClass0(String name, boolean resolve, boolean checkOther) throws ClassNotFoundException
private Class<?> findClass0(String name, boolean checkOther) throws ClassNotFoundException
{
try
{
return super.loadClass( name, resolve );
return super.findClass( name );
} catch ( ClassNotFoundException ex )
{
}
@ -43,7 +53,7 @@ public class PluginClassloader extends URLClassLoader
{
try
{
return loader.loadClass0( name, resolve, false );
return loader.findClass0( name, false );
} catch ( ClassNotFoundException ex )
{
}
@ -52,4 +62,17 @@ public class PluginClassloader extends URLClassLoader
}
throw new ClassNotFoundException( name );
}
void init(Plugin plugin)
{
Preconditions.checkArgument( plugin != null, "plugin" );
Preconditions.checkArgument( plugin.getClass().getClassLoader() == this, "Plugin has incorrect ClassLoader" );
if ( this.plugin != null )
{
throw new IllegalArgumentException( "Plugin already initialized!" );
}
this.plugin = plugin;
plugin.init( proxy, desc );
}
}

View File

@ -320,14 +320,13 @@ public class PluginManager
{
try
{
URLClassLoader loader = new PluginClassloader( new URL[]
URLClassLoader loader = new PluginClassloader( proxy, plugin, new URL[]
{
plugin.getFile().toURI().toURL()
} );
Class<?> main = loader.loadClass( plugin.getMain() );
Plugin clazz = (Plugin) main.getDeclaredConstructor().newInstance();
clazz.init( proxy, plugin );
plugins.put( plugin.getName(), clazz );
clazz.onLoad();
ProxyServer.getInstance().getLogger().log( Level.INFO, "Loaded plugin {0} version {1} by {2}", new Object[]

View File

@ -1,11 +1,12 @@
package net.md_5.bungee.api.plugin;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class DummyPlugin extends Plugin
public final class DummyPlugin extends Plugin
{
public static final DummyPlugin INSTANCE = new DummyPlugin();
private DummyPlugin()
{
super( null, null );
}
}