summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland Levillain <rpl@google.com>2016-05-24 12:46:39 +0000
committerandroid-build-merger <android-build-merger@google.com>2016-05-24 12:46:39 +0000
commit980d276cde20a9c751f0696489b7b63955add187 (patch)
tree18eded8251de466849912d8e77af50b8cb049f44
parentafa1085ebb28dc569c9be4bb730db5e4ab566e25 (diff)
parent31349988d7c44fe453bde9525fd10a371e543c28 (diff)
downloadandroid_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.h4
-rw-r--r--runtime/dex_file_verifier.cc56
-rw-r--r--runtime/dex_file_verifier_test.cc176
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