mirror of
https://github.com/corda/corda.git
synced 2025-02-21 01:42:24 +00:00
CORDA-2667: Fix DJVM SourceClassLoader so that ASM will use it only to load classes from outside the sandbox. (#4804)
This commit is contained in:
parent
3a89bc774e
commit
136f6a6be6
@ -51,6 +51,22 @@ shadowJar {
|
||||
baseName 'corda-djvm'
|
||||
classifier ''
|
||||
relocate 'org.objectweb.asm', 'djvm.org.objectweb.asm'
|
||||
|
||||
// These particular classes are only needed to "bootstrap"
|
||||
// the compilation of the other sandbox classes. At runtime,
|
||||
// we will generate better versions from deterministic-rt.jar.
|
||||
exclude 'sandbox/java/lang/Appendable.class'
|
||||
exclude 'sandbox/java/lang/CharSequence.class'
|
||||
exclude 'sandbox/java/lang/Character\$Subset.class'
|
||||
exclude 'sandbox/java/lang/Character\$Unicode*.class'
|
||||
exclude 'sandbox/java/lang/Comparable.class'
|
||||
exclude 'sandbox/java/lang/Enum.class'
|
||||
exclude 'sandbox/java/lang/Iterable.class'
|
||||
exclude 'sandbox/java/lang/StackTraceElement.class'
|
||||
exclude 'sandbox/java/lang/StringBuffer.class'
|
||||
exclude 'sandbox/java/lang/StringBuilder.class'
|
||||
exclude 'sandbox/java/nio/**'
|
||||
exclude 'sandbox/java/util/**'
|
||||
}
|
||||
assemble.dependsOn shadowJar
|
||||
|
||||
|
@ -84,23 +84,25 @@ class ClassResolver(
|
||||
* Reverse the resolution of a class name.
|
||||
*/
|
||||
fun reverse(resolvedClassName: String): String {
|
||||
if (resolvedClassName in pinnedClasses || resolvedClassName in templateClasses) {
|
||||
return resolvedClassName
|
||||
return if (resolvedClassName in pinnedClasses || resolvedClassName in templateClasses) {
|
||||
resolvedClassName
|
||||
} else {
|
||||
removeSandboxPrefix(resolvedClassName)
|
||||
}
|
||||
if (resolvedClassName.startsWith(sandboxPrefix)) {
|
||||
val nameWithoutPrefix = resolvedClassName.drop(sandboxPrefix.length)
|
||||
if (resolve(nameWithoutPrefix) == resolvedClassName) {
|
||||
return nameWithoutPrefix
|
||||
}
|
||||
}
|
||||
return resolvedClassName
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the resolution of a class name from a fully qualified normalized name.
|
||||
*/
|
||||
fun reverseNormalized(name: String): String {
|
||||
return reverse(name.asResourcePath).asPackagePath
|
||||
fun reverseNormalized(className: String): String {
|
||||
return reverse(className.asResourcePath).asPackagePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the equivalent class name outside the sandbox from a fully qualified normalized name.
|
||||
*/
|
||||
fun toSourceNormalized(className: String): String {
|
||||
return toSource(className.asResourcePath).asPackagePath
|
||||
}
|
||||
|
||||
/**
|
||||
@ -114,6 +116,28 @@ class ClassResolver(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a class name to its equivalent class outside the sandbox.
|
||||
* Needed by [net.corda.djvm.source.AbstractSourceClassLoader].
|
||||
*/
|
||||
private fun toSource(className: String): String {
|
||||
return if (className in pinnedClasses) {
|
||||
className
|
||||
} else {
|
||||
removeSandboxPrefix(className)
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeSandboxPrefix(className: String): String {
|
||||
if (className.startsWith(sandboxPrefix)) {
|
||||
val nameWithoutPrefix = className.drop(sandboxPrefix.length)
|
||||
if (resolve(nameWithoutPrefix) == className) {
|
||||
return nameWithoutPrefix
|
||||
}
|
||||
}
|
||||
return className
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if class is whitelisted or pinned.
|
||||
*/
|
||||
|
@ -7,6 +7,7 @@ import net.corda.djvm.code.ClassMutator
|
||||
import net.corda.djvm.code.EmitterModule
|
||||
import net.corda.djvm.code.emptyAsNull
|
||||
import net.corda.djvm.references.Member
|
||||
import net.corda.djvm.source.AbstractSourceClassLoader
|
||||
import net.corda.djvm.utilities.loggerFor
|
||||
import org.objectweb.asm.ClassReader
|
||||
import org.objectweb.asm.ClassVisitor
|
||||
@ -17,11 +18,11 @@ import org.objectweb.asm.MethodVisitor
|
||||
* Functionality for rewriting parts of a class as it is being loaded.
|
||||
*
|
||||
* @property configuration The configuration of the sandbox.
|
||||
* @property classLoader The class loader used to load the classes that are to be rewritten.
|
||||
* @property classLoader The class loader used to load the source classes that are to be rewritten.
|
||||
*/
|
||||
open class ClassRewriter(
|
||||
private val configuration: SandboxConfiguration,
|
||||
private val classLoader: ClassLoader
|
||||
private val classLoader: AbstractSourceClassLoader
|
||||
) {
|
||||
private val analysisConfig = configuration.analysisConfiguration
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.corda.djvm.rewiring
|
||||
|
||||
import net.corda.djvm.code.asPackagePath
|
||||
import net.corda.djvm.source.AbstractSourceClassLoader
|
||||
import org.objectweb.asm.ClassReader
|
||||
import org.objectweb.asm.ClassWriter
|
||||
import org.objectweb.asm.ClassWriter.COMPUTE_FRAMES
|
||||
@ -22,28 +23,28 @@ import org.objectweb.asm.Type
|
||||
*/
|
||||
open class SandboxClassWriter(
|
||||
classReader: ClassReader,
|
||||
private val cloader: ClassLoader,
|
||||
private val cloader: AbstractSourceClassLoader,
|
||||
flags: Int = COMPUTE_FRAMES or COMPUTE_MAXS
|
||||
) : ClassWriter(classReader, flags) {
|
||||
|
||||
override fun getClassLoader(): ClassLoader = cloader
|
||||
override fun getClassLoader(): AbstractSourceClassLoader = cloader
|
||||
|
||||
/**
|
||||
* Get the common super type of [type1] and [type2].
|
||||
*/
|
||||
override fun getCommonSuperClass(type1: String, type2: String): String {
|
||||
// Need to override [getCommonSuperClass] to ensure that we use ClassLoader.loadClass().
|
||||
// Need to override [getCommonSuperClass] to ensure that we use SourceClassLoader.loadSourceClass().
|
||||
when {
|
||||
type1 == OBJECT_NAME -> return type1
|
||||
type2 == OBJECT_NAME -> return type2
|
||||
}
|
||||
val class1 = try {
|
||||
classLoader.loadClass(type1.asPackagePath)
|
||||
classLoader.loadSourceClass(type1.asPackagePath)
|
||||
} catch (exception: Exception) {
|
||||
throw TypeNotPresentException(type1, exception)
|
||||
}
|
||||
val class2 = try {
|
||||
classLoader.loadClass(type2.asPackagePath)
|
||||
classLoader.loadSourceClass(type2.asPackagePath)
|
||||
} catch (exception: Exception) {
|
||||
throw TypeNotPresentException(type2, exception)
|
||||
}
|
||||
|
@ -47,29 +47,21 @@ abstract class AbstractSourceClassLoader(
|
||||
|
||||
return try {
|
||||
logger.trace("Opening ClassReader for class {}...", originalName)
|
||||
getResourceAsStream("$originalName.class")?.use {
|
||||
ClassReader(it)
|
||||
} ?: run(::throwClassLoadingError)
|
||||
getResourceAsStream("$originalName.class")?.use(::ClassReader) ?: run(::throwClassLoadingError)
|
||||
} catch (exception: IOException) {
|
||||
throwClassLoadingError()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and load the class with the specified name from the search path.
|
||||
*/
|
||||
override fun findClass(name: String): Class<*> {
|
||||
logger.trace("Finding class {}...", name)
|
||||
val originalName = classResolver.reverseNormalized(name)
|
||||
return super.findClass(originalName)
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the class with the specified binary name.
|
||||
*/
|
||||
override fun loadClass(name: String, resolve: Boolean): Class<*> {
|
||||
logger.trace("Loading class {}, resolve={}...", name, resolve)
|
||||
val originalName = classResolver.reverseNormalized(name).let { n ->
|
||||
@Throws(ClassNotFoundException::class)
|
||||
fun loadSourceClass(name: String): Class<*> {
|
||||
logger.trace("Loading source class {}...", name)
|
||||
// We need the name of the equivalent class outside of the sandbox.
|
||||
// This class is expected to belong to the application classloader.
|
||||
val originalName = classResolver.toSourceNormalized(name).let { n ->
|
||||
// A synthetic exception should be mapped back to its
|
||||
// corresponding exception in the original hierarchy.
|
||||
if (isDJVMException(n)) {
|
||||
@ -78,7 +70,7 @@ abstract class AbstractSourceClassLoader(
|
||||
n
|
||||
}
|
||||
}
|
||||
return super.loadClass(originalName, resolve)
|
||||
return loadClass(originalName)
|
||||
}
|
||||
|
||||
protected companion object {
|
||||
|
Loading…
x
Reference in New Issue
Block a user