mirror of
https://github.com/corda/corda.git
synced 2025-06-18 07:08:15 +00:00
CORDA-3715: Check contract classes hav… (#6155)
* CORDA-3715: When loading cordapps now check that contract classes have class version between 49 and 52 * CORDA-3715: Now check class version when contract verification takes place. * CORDA-3715: Making detekt happy with number of levels in func * CORDA-3715: Make use of new ClassGraph release which provides class file major version number. * CORDA-3715: Changed package name in test jars * CORDA-3715: Use ClassGraph when loading attachments. * CORDA-3715: Reverted file to 4.5 version * CORDA-3715: Updating method to match non deterministic version. * CORDA-3715: Added in default param. * CORDA-3715: Adjusted min JDK version to 1.1 * CORDA-3715: Switching check to JDK 1.2 * CORDA-3715: Now version check SerializationWhitelist classes. * CORDA-3715: Switched default to null for range.
This commit is contained in:
@ -337,6 +337,8 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
|
||||
class InvalidAttachmentException(txId: SecureHash, @Suppress("unused") val attachmentHash: AttachmentId) : TransactionVerificationException(txId,
|
||||
"The attachment $attachmentHash is not a valid ZIP or JAR file.".trimIndent(), null)
|
||||
|
||||
class UnsupportedClassVersionError(txId: SecureHash, message: String, cause: Throwable) : TransactionVerificationException(txId, message, cause)
|
||||
|
||||
// TODO: Make this descend from TransactionVerificationException so that untrusted attachments cause flows to be hospitalized.
|
||||
/** Thrown during classloading upon encountering an untrusted attachment (eg. not in the [TRUSTED_UPLOADERS] list) */
|
||||
@KeepForDJVM
|
||||
|
@ -9,17 +9,20 @@ import net.corda.core.serialization.internal.AttachmentURLStreamHandlerFactory.a
|
||||
* Creates instances of all the classes in the classpath of the provided classloader, which implement the interface of the provided class.
|
||||
* @param classloader the classloader, which will be searched for the classes.
|
||||
* @param clazz the class of the interface, which the classes - to be returned - must implement.
|
||||
* @param classVersionRange if specified an exception is raised if class version is not within the passed range.
|
||||
*
|
||||
* @return instances of the identified classes.
|
||||
* @throws IllegalArgumentException if the classes found do not have proper constructors.
|
||||
* @throws UnsupportedClassVersionError if the class version is not within range.
|
||||
*
|
||||
* Note: In order to be instantiated, the associated classes must:
|
||||
* - be non-abstract
|
||||
* - either be a Kotlin object or have a constructor with no parameters (or only optional ones)
|
||||
*/
|
||||
@StubOutForDJVM
|
||||
fun <T: Any> createInstancesOfClassesImplementing(classloader: ClassLoader, clazz: Class<T>): Set<T> {
|
||||
return getNamesOfClassesImplementing(classloader, clazz)
|
||||
fun <T: Any> createInstancesOfClassesImplementing(classloader: ClassLoader, clazz: Class<T>,
|
||||
classVersionRange: IntRange? = null): Set<T> {
|
||||
return getNamesOfClassesImplementing(classloader, clazz, classVersionRange)
|
||||
.map { classloader.loadClass(it).asSubclass(clazz) }
|
||||
.mapTo(LinkedHashSet()) { it.kotlin.objectOrNewInstance() }
|
||||
}
|
||||
@ -28,17 +31,26 @@ fun <T: Any> createInstancesOfClassesImplementing(classloader: ClassLoader, claz
|
||||
* Scans for all the non-abstract classes in the classpath of the provided classloader which implement the interface of the provided class.
|
||||
* @param classloader the classloader, which will be searched for the classes.
|
||||
* @param clazz the class of the interface, which the classes - to be returned - must implement.
|
||||
* @param classVersionRange if specified an exception is raised if class version is not within the passed range.
|
||||
*
|
||||
* @return names of the identified classes.
|
||||
* @throws UnsupportedClassVersionError if the class version is not within range.
|
||||
*/
|
||||
@StubOutForDJVM
|
||||
fun <T: Any> getNamesOfClassesImplementing(classloader: ClassLoader, clazz: Class<T>): Set<String> {
|
||||
fun <T: Any> getNamesOfClassesImplementing(classloader: ClassLoader, clazz: Class<T>,
|
||||
classVersionRange: IntRange? = null): Set<String> {
|
||||
return ClassGraph().overrideClassLoaders(classloader)
|
||||
.enableURLScheme(attachmentScheme)
|
||||
.ignoreParentClassLoaders()
|
||||
.enableClassInfo()
|
||||
.pooledScan()
|
||||
.use { result ->
|
||||
classVersionRange?.let {
|
||||
result.allClasses.firstOrNull { c -> c.classfileMajorVersion !in classVersionRange }?.also {
|
||||
throw UnsupportedClassVersionError("Class ${it.name} found in ${it.classpathElementURL} " +
|
||||
"has an unsupported class version of ${it.classfileMajorVersion}")
|
||||
}
|
||||
}
|
||||
result.getClassesImplementing(clazz.name)
|
||||
.filterNot(ClassInfo::isAbstract)
|
||||
.mapTo(LinkedHashSet(), ClassInfo::getName)
|
||||
|
@ -636,3 +636,6 @@ fun Logger.warnOnce(warning: String) {
|
||||
this.warn(warning)
|
||||
}
|
||||
}
|
||||
|
||||
const val JDK1_2_CLASS_FILE_FORMAT_MAJOR_VERSION = 46
|
||||
const val JDK8_CLASS_FILE_FORMAT_MAJOR_VERSION = 52
|
||||
|
@ -323,7 +323,13 @@ object AttachmentsClassLoaderBuilder {
|
||||
val serializationContext = cache.computeIfAbsent(Key(attachmentIds, params)) {
|
||||
// Create classloader and load serializers, whitelisted classes
|
||||
val transactionClassLoader = AttachmentsClassLoader(attachments, params, txId, isAttachmentTrusted, parent)
|
||||
val serializers = createInstancesOfClassesImplementing(transactionClassLoader, SerializationCustomSerializer::class.java)
|
||||
val serializers = try {
|
||||
createInstancesOfClassesImplementing(transactionClassLoader, SerializationCustomSerializer::class.java,
|
||||
JDK1_2_CLASS_FILE_FORMAT_MAJOR_VERSION..JDK8_CLASS_FILE_FORMAT_MAJOR_VERSION)
|
||||
}
|
||||
catch(ex: UnsupportedClassVersionError) {
|
||||
throw TransactionVerificationException.UnsupportedClassVersionError(txId, ex.message!!, ex)
|
||||
}
|
||||
val whitelistedClasses = ServiceLoader.load(SerializationWhitelist::class.java, transactionClassLoader)
|
||||
.flatMap(SerializationWhitelist::whitelist)
|
||||
|
||||
|
Reference in New Issue
Block a user