diff options
author | Roland Levillain <rpl@google.com> | 2016-05-24 12:46:39 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2016-05-24 12:46:39 +0000 |
commit | 980d276cde20a9c751f0696489b7b63955add187 (patch) | |
tree | 18eded8251de466849912d8e77af50b8cb049f44 | |
parent | afa1085ebb28dc569c9be4bb730db5e4ab566e25 (diff) | |
parent | 31349988d7c44fe453bde9525fd10a371e543c28 (diff) | |
download | android_art-980d276cde20a9c751f0696489b7b63955add187.tar.gz android_art-980d276cde20a9c751f0696489b7b63955add187.tar.bz2 android_art-980d276cde20a9c751f0696489b7b63955add187.zip |
Enforce class definition ordering rules in v37 Dex files.
am: 31349988d7
* commit '31349988d7c44fe453bde9525fd10a371e543c28':
Enforce class definition ordering rules in v37 Dex files.
Change-Id: Ie6a437bc417a3ed30f1040f69b2beb66d3bbc635
-rw-r--r-- | runtime/dex_file.h | 4 | ||||
-rw-r--r-- | runtime/dex_file_verifier.cc | 56 | ||||
-rw-r--r-- | runtime/dex_file_verifier_test.cc | 176 |
3 files changed, 234 insertions, 2 deletions
diff --git a/runtime/dex_file.h b/runtime/dex_file.h index ce7f62acb5..638821bfb7 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -57,7 +57,11 @@ class ZipArchive; // TODO: move all of the macro functionality into the DexCache class. class DexFile { public: + // First Dex format version supporting default methods. static const uint32_t kDefaultMethodsVersion = 37; + // First Dex format version enforcing class definition ordering rules. + static const uint32_t kClassDefinitionOrderEnforcedVersion = 37; + static const uint8_t kDexMagic[]; static constexpr size_t kNumDexVersions = 2; static constexpr size_t kDexVersionLen = 4; diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc index bbffbbb7b7..d2e84ad5c0 100644 --- a/runtime/dex_file_verifier.cc +++ b/runtime/dex_file_verifier.cc @@ -1956,6 +1956,31 @@ bool DexFileVerifier::CheckInterClassDefItem() { } if (item->superclass_idx_ != DexFile::kDexNoIndex16) { + if (header_->GetVersion() >= DexFile::kClassDefinitionOrderEnforcedVersion) { + // Check that a class does not inherit from itself directly (by having + // the same type idx as its super class). + if (UNLIKELY(item->superclass_idx_ == item->class_idx_)) { + ErrorStringPrintf("Class with same type idx as its superclass: '%d'", item->class_idx_); + return false; + } + + // Check that a class is defined after its super class (if the + // latter is defined in the same Dex file). + const DexFile::ClassDef* superclass_def = dex_file_->FindClassDef(item->superclass_idx_); + if (superclass_def != nullptr) { + // The superclass is defined in this Dex file. + if (superclass_def > item) { + // ClassDef item for super class appearing after the class' ClassDef item. + ErrorStringPrintf("Invalid class definition ordering:" + " class with type idx: '%d' defined before" + " superclass with type idx: '%d'", + item->class_idx_, + item->superclass_idx_); + return false; + } + } + } + LOAD_STRING_BY_TYPE(superclass_descriptor, item->superclass_idx_, "inter_class_def_item superclass_idx") if (UNLIKELY(!IsValidDescriptor(superclass_descriptor) || superclass_descriptor[0] != 'L')) { @@ -1964,12 +1989,39 @@ bool DexFileVerifier::CheckInterClassDefItem() { } } + // Check interfaces. const DexFile::TypeList* interfaces = dex_file_->GetInterfacesList(*item); if (interfaces != nullptr) { uint32_t size = interfaces->Size(); - - // Ensure that all interfaces refer to classes (not arrays or primitives). for (uint32_t i = 0; i < size; i++) { + if (header_->GetVersion() >= DexFile::kClassDefinitionOrderEnforcedVersion) { + // Check that a class does not implement itself directly (by having the + // same type idx as one of its immediate implemented interfaces). + if (UNLIKELY(interfaces->GetTypeItem(i).type_idx_ == item->class_idx_)) { + ErrorStringPrintf("Class with same type idx as implemented interface: '%d'", + item->class_idx_); + return false; + } + + // Check that a class is defined after the interfaces it implements + // (if they are defined in the same Dex file). + const DexFile::ClassDef* interface_def = + dex_file_->FindClassDef(interfaces->GetTypeItem(i).type_idx_); + if (interface_def != nullptr) { + // The interface is defined in this Dex file. + if (interface_def > item) { + // ClassDef item for interface appearing after the class' ClassDef item. + ErrorStringPrintf("Invalid class definition ordering:" + " class with type idx: '%d' defined before" + " implemented interface with type idx: '%d'", + item->class_idx_, + interfaces->GetTypeItem(i).type_idx_); + return false; + } + } + } + + // Ensure that the interface refers to a class (not an array nor a primitive type). LOAD_STRING_BY_TYPE(inf_descriptor, interfaces->GetTypeItem(i).type_idx_, "inter_class_def_item interface type_idx") if (UNLIKELY(!IsValidDescriptor(inf_descriptor) || inf_descriptor[0] != 'L')) { diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc index 3741c1e76c..4e53914374 100644 --- a/runtime/dex_file_verifier_test.cc +++ b/runtime/dex_file_verifier_test.cc @@ -184,6 +184,12 @@ static std::unique_ptr<const DexFile> OpenDexFileBase64(const char* base64, return dex_file; } +// To generate a base64 encoded Dex file (such as kGoodTestDex, below) +// from Smali files, use: +// +// smali -o classes.dex class1.smali [class2.smali ...] +// base64 classes.dex >classes.dex.base64 + // For reference. static const char kGoodTestDex[] = "ZGV4CjAzNQDrVbyVkxX1HljTznNf95AglkUAhQuFtmKkAgAAcAAAAHhWNBIAAAAAAAAAAAQCAAAN" @@ -1521,4 +1527,174 @@ TEST_F(DexFileVerifierTest, ProtoOrdering) { } } +// To generate a base64 encoded Dex file version 037 from Smali files, use: +// +// smali --api-level 24 -o classes.dex class1.smali [class2.smali ...] +// base64 classes.dex >classes.dex.base64 + +// Dex file version 037 generated from: +// +// .class public LB28685551; +// .super LB28685551; + +static const char kClassExtendsItselfTestDex[] = + "ZGV4CjAzNwDeGbgRg1kb6swszpcTWrrOAALB++F4OPT0AAAAcAAAAHhWNBIAAAAAAAAAAKgAAAAB" + "AAAAcAAAAAEAAAB0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAHgAAABcAAAAmAAAAJgA" + "AAAAAAAAAAAAAAEAAAAAAAAAAAAAAP////8AAAAAAAAAAAAAAAALTEIyODY4NTU1MTsAAAAABgAA" + "AAAAAAABAAAAAAAAAAEAAAABAAAAcAAAAAIAAAABAAAAdAAAAAYAAAABAAAAeAAAAAIgAAABAAAA" + "mAAAAAAQAAABAAAAqAAAAA=="; + +TEST_F(DexFileVerifierTest, ClassExtendsItself) { + VerifyModification( + kClassExtendsItselfTestDex, + "class_extends_itself", + [](DexFile* dex_file ATTRIBUTE_UNUSED) { /* empty */ }, + "Class with same type idx as its superclass: '0'"); +} + +// Dex file version 037 generated from: +// +// .class public LFoo; +// .super LBar; +// +// and: +// +// .class public LBar; +// .super LFoo; + +static const char kClassesExtendOneAnotherTestDex[] = + "ZGV4CjAzNwBXHSrwpDMwRBkg+L+JeQCuFNRLhQ86duEcAQAAcAAAAHhWNBIAAAAAAAAAANAAAAAC" + "AAAAcAAAAAIAAAB4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAIAAAABcAAAAwAAAAMAA" + "AADHAAAAAAAAAAEAAAABAAAAAQAAAAAAAAAAAAAA/////wAAAAAAAAAAAAAAAAAAAAABAAAAAQAA" + "AAAAAAD/////AAAAAAAAAAAAAAAABUxCYXI7AAVMRm9vOwAAAAYAAAAAAAAAAQAAAAAAAAABAAAA" + "AgAAAHAAAAACAAAAAgAAAHgAAAAGAAAAAgAAAIAAAAACIAAAAgAAAMAAAAAAEAAAAQAAANAAAAA="; + +TEST_F(DexFileVerifierTest, ClassesExtendOneAnother) { + VerifyModification( + kClassesExtendOneAnotherTestDex, + "classes_extend_one_another", + [](DexFile* dex_file ATTRIBUTE_UNUSED) { /* empty */ }, + "Invalid class definition ordering: class with type idx: '1' defined before" + " superclass with type idx: '0'"); +} + +// Dex file version 037 generated from: +// +// .class public LAll; +// .super LYour; +// +// and: +// +// .class public LYour; +// .super LBase; +// +// and: +// +// .class public LBase; +// .super LAll; + +static const char kCircularClassInheritanceTestDex[] = + "ZGV4CjAzNwBMJxgP0SJz6oLXnKfl+J7lSEORLRwF5LNMAQAAcAAAAHhWNBIAAAAAAAAAAAABAAAD" + "AAAAcAAAAAMAAAB8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAIgAAABkAAAA6AAAAOgA" + "AADvAAAA9wAAAAAAAAABAAAAAgAAAAEAAAABAAAAAAAAAAAAAAD/////AAAAAAAAAAAAAAAAAgAA" + "AAEAAAABAAAAAAAAAP////8AAAAAAAAAAAAAAAAAAAAAAQAAAAIAAAAAAAAA/////wAAAAAAAAAA" + "AAAAAAVMQWxsOwAGTEJhc2U7AAZMWW91cjsAAAYAAAAAAAAAAQAAAAAAAAABAAAAAwAAAHAAAAAC" + "AAAAAwAAAHwAAAAGAAAAAwAAAIgAAAACIAAAAwAAAOgAAAAAEAAAAQAAAAABAAA="; + +TEST_F(DexFileVerifierTest, CircularClassInheritance) { + VerifyModification( + kCircularClassInheritanceTestDex, + "circular_class_inheritance", + [](DexFile* dex_file ATTRIBUTE_UNUSED) { /* empty */ }, + "Invalid class definition ordering: class with type idx: '1' defined before" + " superclass with type idx: '0'"); +} + +// Dex file version 037 generated from: +// +// .class public abstract interface LInterfaceImplementsItself; +// .super Ljava/lang/Object; +// .implements LInterfaceImplementsItself; + +static const char kInterfaceImplementsItselfTestDex[] = + "ZGV4CjAzNwCKKrjatp8XbXl5S/bEVJnqaBhjZkQY4440AQAAcAAAAHhWNBIAAAAAAAAAANwAAAAC" + "AAAAcAAAAAIAAAB4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAIAAAACUAAAAoAAAAKAA" + "AAC9AAAAAAAAAAEAAAAAAAAAAQYAAAEAAADUAAAA/////wAAAAAAAAAAAAAAABtMSW50ZXJmYWNl" + "SW1wbGVtZW50c0l0c2VsZjsAEkxqYXZhL2xhbmcvT2JqZWN0OwAAAAABAAAAAAAAAAcAAAAAAAAA" + "AQAAAAAAAAABAAAAAgAAAHAAAAACAAAAAgAAAHgAAAAGAAAAAQAAAIAAAAACIAAAAgAAAKAAAAAB" + "EAAAAQAAANQAAAAAEAAAAQAAANwAAAA="; + +TEST_F(DexFileVerifierTest, InterfaceImplementsItself) { + VerifyModification( + kInterfaceImplementsItselfTestDex, + "interface_implements_itself", + [](DexFile* dex_file ATTRIBUTE_UNUSED) { /* empty */ }, + "Class with same type idx as implemented interface: '0'"); +} + +// Dex file version 037 generated from: +// +// .class public abstract interface LPing; +// .super Ljava/lang/Object; +// .implements LPong; +// +// and: +// +// .class public abstract interface LPong; +// .super Ljava/lang/Object; +// .implements LPing; + +static const char kInterfacesImplementOneAnotherTestDex[] = + "ZGV4CjAzNwD0Kk9sxlYdg3Dy1Cff0gQCuJAQfEP6ohZUAQAAcAAAAHhWNBIAAAAAAAAAAPwAAAAD" + "AAAAcAAAAAMAAAB8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAIgAAACMAAAAyAAAAMgA" + "AADQAAAA2AAAAAAAAAABAAAAAgAAAAEAAAABBgAAAgAAAOwAAAD/////AAAAAAAAAAAAAAAAAAAA" + "AAEGAAACAAAA9AAAAP////8AAAAAAAAAAAAAAAAGTFBpbmc7AAZMUG9uZzsAEkxqYXZhL2xhbmcv" + "T2JqZWN0OwABAAAAAAAAAAEAAAABAAAABwAAAAAAAAABAAAAAAAAAAEAAAADAAAAcAAAAAIAAAAD" + "AAAAfAAAAAYAAAACAAAAiAAAAAIgAAADAAAAyAAAAAEQAAACAAAA7AAAAAAQAAABAAAA/AAAAA=="; + +TEST_F(DexFileVerifierTest, InterfacesImplementOneAnother) { + VerifyModification( + kInterfacesImplementOneAnotherTestDex, + "interfaces_implement_one_another", + [](DexFile* dex_file ATTRIBUTE_UNUSED) { /* empty */ }, + "Invalid class definition ordering: class with type idx: '1' defined before" + " implemented interface with type idx: '0'"); +} + +// Dex file version 037 generated from: +// +// .class public abstract interface LA; +// .super Ljava/lang/Object; +// .implements LB; +// +// and: +// +// .class public abstract interface LB; +// .super Ljava/lang/Object; +// .implements LC; +// +// and: +// +// .class public abstract interface LC; +// .super Ljava/lang/Object; +// .implements LA; + +static const char kCircularInterfaceImplementationTestDex[] = + "ZGV4CjAzNwCzKmD5Fol6XAU6ichYHcUTIP7Z7MdTcEmEAQAAcAAAAHhWNBIAAAAAAAAAACwBAAAE" + "AAAAcAAAAAQAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAJAAAACUAAAA8AAAAPAA" + "AAD1AAAA+gAAAP8AAAAAAAAAAQAAAAIAAAADAAAAAgAAAAEGAAADAAAAHAEAAP////8AAAAAAAAA" + "AAAAAAABAAAAAQYAAAMAAAAUAQAA/////wAAAAAAAAAAAAAAAAAAAAABBgAAAwAAACQBAAD/////" + "AAAAAAAAAAAAAAAAA0xBOwADTEI7AANMQzsAEkxqYXZhL2xhbmcvT2JqZWN0OwAAAQAAAAIAAAAB" + "AAAAAAAAAAEAAAABAAAABwAAAAAAAAABAAAAAAAAAAEAAAAEAAAAcAAAAAIAAAAEAAAAgAAAAAYA" + "AAADAAAAkAAAAAIgAAAEAAAA8AAAAAEQAAADAAAAFAEAAAAQAAABAAAALAEAAA=="; + +TEST_F(DexFileVerifierTest, CircularInterfaceImplementation) { + VerifyModification( + kCircularInterfaceImplementationTestDex, + "circular_interface_implementation", + [](DexFile* dex_file ATTRIBUTE_UNUSED) { /* empty */ }, + "Invalid class definition ordering: class with type idx: '2' defined before" + " implemented interface with type idx: '0'"); +} + } // namespace art |