mirror of
https://github.com/PaperMC/Paper.git
synced 2024-11-01 00:10:32 +01:00
Address todos
This commit is contained in:
parent
be53945cc0
commit
dafde7ed62
@ -6,31 +6,42 @@ Subject: [PATCH] Modify library loader jars bytecode
|
|||||||
|
|
||||||
diff --git a/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/BytecodeModifyingURLClassLoader.java b/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/BytecodeModifyingURLClassLoader.java
|
diff --git a/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/BytecodeModifyingURLClassLoader.java b/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/BytecodeModifyingURLClassLoader.java
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000000000000000000000000000000000000..acd24b8d32b5debd987f463c0be0ac6bdfdd061f
|
index 0000000000000000000000000000000000000000..405416dc3d1c8c58b4e0c880d8751ca319188f62
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/BytecodeModifyingURLClassLoader.java
|
+++ b/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/BytecodeModifyingURLClassLoader.java
|
||||||
@@ -0,0 +1,116 @@
|
@@ -0,0 +1,185 @@
|
||||||
+package io.papermc.paper.plugin.entrypoint.classloader;
|
+package io.papermc.paper.plugin.entrypoint.classloader;
|
||||||
+
|
+
|
||||||
+import io.papermc.paper.pluginremap.reflect.ReflectionRemapper;
|
+import io.papermc.paper.pluginremap.reflect.ReflectionRemapper;
|
||||||
+import java.io.IOException;
|
+import java.io.IOException;
|
||||||
+import java.io.InputStream;
|
+import java.io.InputStream;
|
||||||
|
+import java.io.UncheckedIOException;
|
||||||
|
+import java.net.JarURLConnection;
|
||||||
+import java.net.URL;
|
+import java.net.URL;
|
||||||
+import java.net.URLClassLoader;
|
+import java.net.URLClassLoader;
|
||||||
+import java.security.CodeSigner;
|
+import java.security.CodeSigner;
|
||||||
+import java.security.CodeSource;
|
+import java.security.CodeSource;
|
||||||
|
+import java.util.Map;
|
||||||
|
+import java.util.concurrent.ConcurrentHashMap;
|
||||||
+import java.util.function.Function;
|
+import java.util.function.Function;
|
||||||
|
+import java.util.jar.Attributes;
|
||||||
+import java.util.jar.Manifest;
|
+import java.util.jar.Manifest;
|
||||||
|
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
+import org.objectweb.asm.ClassReader;
|
+import org.objectweb.asm.ClassReader;
|
||||||
+import org.objectweb.asm.ClassVisitor;
|
+import org.objectweb.asm.ClassVisitor;
|
||||||
+import org.objectweb.asm.ClassWriter;
|
+import org.objectweb.asm.ClassWriter;
|
||||||
+
|
+
|
||||||
|
+import static java.util.Objects.requireNonNullElse;
|
||||||
|
+
|
||||||
+public final class BytecodeModifyingURLClassLoader extends URLClassLoader {
|
+public final class BytecodeModifyingURLClassLoader extends URLClassLoader {
|
||||||
+ static {
|
+ static {
|
||||||
+ ClassLoader.registerAsParallelCapable();
|
+ ClassLoader.registerAsParallelCapable();
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
|
+ private static final Object MISSING_MANIFEST = new Object();
|
||||||
|
+
|
||||||
+ private final Function<byte[], byte[]> modifier;
|
+ private final Function<byte[], byte[]> modifier;
|
||||||
|
+ private final Map<String, Object> manifests = new ConcurrentHashMap<>();
|
||||||
+
|
+
|
||||||
+ public BytecodeModifyingURLClassLoader(
|
+ public BytecodeModifyingURLClassLoader(
|
||||||
+ final URL[] urls,
|
+ final URL[] urls,
|
||||||
@ -65,20 +76,8 @@ index 0000000000000000000000000000000000000000..acd24b8d32b5debd987f463c0be0ac6b
|
|||||||
+ if (url != null) {
|
+ if (url != null) {
|
||||||
+ try {
|
+ try {
|
||||||
+ result = this.defineClass(name, url);
|
+ result = this.defineClass(name, url);
|
||||||
+ } catch (IOException e) {
|
+ } catch (final IOException e) {
|
||||||
+ throw new ClassNotFoundException(name, e);
|
+ throw new ClassNotFoundException(name, e);
|
||||||
+ } catch (ClassFormatError e2) {
|
|
||||||
+ /* TODO
|
|
||||||
+ try {
|
|
||||||
+ final Throwable dataError = (Throwable) GET_DATA_ERROR.invoke(res);
|
|
||||||
+ if (dataError != null) {
|
|
||||||
+ e2.addSuppressed(dataError);
|
|
||||||
+ }
|
|
||||||
+ } catch (final ReflectiveOperationException e) {
|
|
||||||
+ throw new RuntimeException(e);
|
|
||||||
+ }
|
|
||||||
+ */
|
|
||||||
+ throw e2;
|
|
||||||
+ }
|
+ }
|
||||||
+ } else {
|
+ } else {
|
||||||
+ result = null;
|
+ result = null;
|
||||||
@ -94,26 +93,24 @@ index 0000000000000000000000000000000000000000..acd24b8d32b5debd987f463c0be0ac6b
|
|||||||
+ if (i != -1) {
|
+ if (i != -1) {
|
||||||
+ String pkgname = name.substring(0, i);
|
+ String pkgname = name.substring(0, i);
|
||||||
+ // Check if package already loaded.
|
+ // Check if package already loaded.
|
||||||
+ Manifest man = null; // (Manifest) GET_MANIFEST.invoke(res); TODO
|
+ final @Nullable Manifest man = this.manifestFor(url);
|
||||||
+ //if (GET_AND_VERIFY_PKG.invoke(this, pkgname, man, url) == null) { // todo
|
+ if (this.getAndVerifyPackage(pkgname, man, url) == null) {
|
||||||
+ try {
|
+ try {
|
||||||
+ if (man != null) {
|
+ if (man != null) {
|
||||||
+ definePackage(pkgname, man, url);
|
+ this.definePackage(pkgname, man, url);
|
||||||
+ } else {
|
+ } else {
|
||||||
+ definePackage(pkgname, null, null, null, null, null, null, null);
|
+ this.definePackage(pkgname, null, null, null, null, null, null, null);
|
||||||
+ }
|
+ }
|
||||||
+ } catch (IllegalArgumentException iae) {
|
+ } catch (IllegalArgumentException iae) {
|
||||||
+ // parallel-capable class loaders: re-verify in case of a
|
+ // parallel-capable class loaders: re-verify in case of a
|
||||||
+ // race condition
|
+ // race condition
|
||||||
+ /* TODO
|
+ if (this.getAndVerifyPackage(pkgname, man, url) == null) {
|
||||||
+ if (GET_AND_VERIFY_PKG.invoke(this, pkgname, man, url) == null) {
|
|
||||||
+ // Should never happen
|
+ // Should never happen
|
||||||
+ throw new AssertionError("Cannot find package " +
|
+ throw new AssertionError("Cannot find package " +
|
||||||
+ pkgname);
|
+ pkgname);
|
||||||
+ }
|
+ }
|
||||||
+ */
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ //} // todo
|
|
||||||
+ }
|
+ }
|
||||||
+ final byte[] bytes;
|
+ final byte[] bytes;
|
||||||
+ try (final InputStream is = url.openStream()) {
|
+ try (final InputStream is = url.openStream()) {
|
||||||
@ -123,7 +120,79 @@ index 0000000000000000000000000000000000000000..acd24b8d32b5debd987f463c0be0ac6b
|
|||||||
+ final byte[] modified = this.modifier.apply(bytes);
|
+ final byte[] modified = this.modifier.apply(bytes);
|
||||||
+
|
+
|
||||||
+ final CodeSource cs = new CodeSource(url, (CodeSigner[]) null);
|
+ final CodeSource cs = new CodeSource(url, (CodeSigner[]) null);
|
||||||
+ return defineClass(name, modified, 0, modified.length, cs);
|
+ return this.defineClass(name, modified, 0, modified.length, cs);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private Package getAndVerifyPackage(
|
||||||
|
+ String pkgname,
|
||||||
|
+ Manifest man, URL url
|
||||||
|
+ ) {
|
||||||
|
+ Package pkg = getDefinedPackage(pkgname);
|
||||||
|
+ if (pkg != null) {
|
||||||
|
+ // Package found, so check package sealing.
|
||||||
|
+ if (pkg.isSealed()) {
|
||||||
|
+ // Verify that code source URL is the same.
|
||||||
|
+ if (!pkg.isSealed(url)) {
|
||||||
|
+ throw new SecurityException(
|
||||||
|
+ "sealing violation: package " + pkgname + " is sealed");
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ // Make sure we are not attempting to seal the package
|
||||||
|
+ // at this code source URL.
|
||||||
|
+ if ((man != null) && this.isSealed(pkgname, man)) {
|
||||||
|
+ throw new SecurityException(
|
||||||
|
+ "sealing violation: can't seal package " + pkgname +
|
||||||
|
+ ": already loaded");
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return pkg;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private boolean isSealed(String name, Manifest man) {
|
||||||
|
+ Attributes attr = man.getAttributes(name.replace('.', '/').concat("/"));
|
||||||
|
+ String sealed = null;
|
||||||
|
+ if (attr != null) {
|
||||||
|
+ sealed = attr.getValue(Attributes.Name.SEALED);
|
||||||
|
+ }
|
||||||
|
+ if (sealed == null) {
|
||||||
|
+ if ((attr = man.getMainAttributes()) != null) {
|
||||||
|
+ sealed = attr.getValue(Attributes.Name.SEALED);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return "true".equalsIgnoreCase(sealed);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private @Nullable Manifest manifestFor(final URL url) throws IOException {
|
||||||
|
+ Manifest man = null;
|
||||||
|
+ if (url.getProtocol().equals("jar")) {
|
||||||
|
+ try {
|
||||||
|
+ final Object computedManifest = this.manifests.computeIfAbsent(jarName(url), $ -> {
|
||||||
|
+ try {
|
||||||
|
+ final Manifest m = ((JarURLConnection) url.openConnection()).getManifest();
|
||||||
|
+ return requireNonNullElse(m, MISSING_MANIFEST);
|
||||||
|
+ } catch (final IOException e) {
|
||||||
|
+ throw new UncheckedIOException(e);
|
||||||
|
+ }
|
||||||
|
+ });
|
||||||
|
+ if (computedManifest instanceof Manifest found) {
|
||||||
|
+ man = found;
|
||||||
|
+ }
|
||||||
|
+ } catch (final UncheckedIOException e) {
|
||||||
|
+ throw e.getCause();
|
||||||
|
+ } catch (final IllegalArgumentException e) {
|
||||||
|
+ throw new IOException(e);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return man;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private static String jarName(final URL sourceUrl) {
|
||||||
|
+ final int exclamationIdx = sourceUrl.getPath().lastIndexOf('!');
|
||||||
|
+ if (exclamationIdx != -1) {
|
||||||
|
+ return sourceUrl.getPath().substring(0, exclamationIdx);
|
||||||
|
+ }
|
||||||
|
+ throw new IllegalArgumentException("Could not find jar for URL " + sourceUrl);
|
||||||
+ }
|
+ }
|
||||||
+}
|
+}
|
||||||
diff --git a/src/main/java/io/papermc/paper/plugin/loader/PaperClasspathBuilder.java b/src/main/java/io/papermc/paper/plugin/loader/PaperClasspathBuilder.java
|
diff --git a/src/main/java/io/papermc/paper/plugin/loader/PaperClasspathBuilder.java b/src/main/java/io/papermc/paper/plugin/loader/PaperClasspathBuilder.java
|
||||||
|
Loading…
Reference in New Issue
Block a user