diff options
author | 2018-01-26 15:45:30 -0800 | |
---|---|---|
committer | 2018-01-29 19:42:40 +0000 | |
commit | 1a824a5c1070648971ce9593a1dd71cdd8cf2f98 (patch) | |
tree | 1ff6d9fd284a4dd2a337165dff20e71137997c9d | |
parent | 0406e1e59970399393f53923704e1b9a828b2173 (diff) |
Remove hiddenapi access flags in FixedUpDexFile
The hiddenapi tool will mess with the access flags of fields and
methods in order to record which are '@hide'. We need to undo this
before passing any dex files down to jvmti agents.
Test: ./test.py --host -j50
Bug: 72550707
Bug: 64382372
Change-Id: Ibc9a96a6b541c06844f276db009ac29514f7a3bb
-rw-r--r-- | openjdkjvmti/fixed_up_dex_file.cc | 16 | ||||
-rw-r--r-- | runtime/leb128.h | 32 | ||||
-rw-r--r-- | runtime/vdex_file.cc | 57 | ||||
-rw-r--r-- | test/983-source-transform-verify/expected.txt | 1 | ||||
-rw-r--r-- | test/983-source-transform-verify/src/art/Test983.java | 4 | ||||
-rw-r--r-- | tools/hiddenapi/hiddenapi.cc | 38 |
6 files changed, 93 insertions, 55 deletions
diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc index 6c66f12bb1..a8d2a37fa6 100644 --- a/openjdkjvmti/fixed_up_dex_file.cc +++ b/openjdkjvmti/fixed_up_dex_file.cc @@ -33,6 +33,7 @@ #include "dex/art_dex_file_loader.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_loader.h" +#include "dex/dex_file_verifier.h" // Runtime includes. #include "dex_container.h" @@ -67,6 +68,20 @@ static void DoDexUnquicken(const art::DexFile& new_dex_file, const art::DexFile& vdex->UnquickenDexFile(new_dex_file, original_dex_file, /* decompile_return_instruction */true); } +static void DCheckVerifyDexFile(const art::DexFile& dex) { + if (art::kIsDebugBuild) { + std::string error; + if (!art::DexFileVerifier::Verify(&dex, + dex.Begin(), + dex.Size(), + "FixedUpDexFile_Verification.dex", + /*verify_checksum*/ true, + &error)) { + LOG(FATAL) << "Failed to verify de-quickened dex file: " << error; + } + } +} + std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(const art::DexFile& original, const char* descriptor) { // Copy the data into mutable memory. @@ -121,6 +136,7 @@ std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(const art::DexFile& origi DoDexUnquicken(*new_dex_file, original); RecomputeDexChecksum(const_cast<art::DexFile*>(new_dex_file.get())); + DCheckVerifyDexFile(*new_dex_file); std::unique_ptr<FixedUpDexFile> ret(new FixedUpDexFile(std::move(new_dex_file), std::move(data))); return ret; } diff --git a/runtime/leb128.h b/runtime/leb128.h index 9fb09d8fc2..07eadc1ddf 100644 --- a/runtime/leb128.h +++ b/runtime/leb128.h @@ -55,6 +55,10 @@ static inline uint32_t DecodeUnsignedLeb128(const uint8_t** data) { return static_cast<uint32_t>(result); } +static inline uint32_t DecodeUnsignedLeb128WithoutMovingCursor(const uint8_t* data) { + return DecodeUnsignedLeb128(&data); +} + static inline bool DecodeUnsignedLeb128Checked(const uint8_t** data, const void* end, uint32_t* out) { @@ -203,6 +207,34 @@ static inline uint32_t UnsignedLeb128Size(uint32_t data) { return (x * 37) >> 8; } +static inline bool IsLeb128Terminator(const uint8_t* ptr) { + return *ptr <= 0x7f; +} + +// Returns the first byte of a Leb128 value assuming that: +// (1) `end_ptr` points to the first byte after the Leb128 value, and +// (2) there is another Leb128 value before this one. +template <typename T> +static inline T* ReverseSearchUnsignedLeb128(T* end_ptr) { + static_assert(std::is_same<typename std::remove_const<T>::type, uint8_t>::value, + "T must be a uint8_t"); + T* ptr = end_ptr; + + // Move one byte back, check that this is the terminating byte. + ptr--; + DCHECK(IsLeb128Terminator(ptr)); + + // Keep moving back while the previous byte is not a terminating byte. + // Fail after reading five bytes in case there isn't another Leb128 value + // before this one. + while (!IsLeb128Terminator(ptr - 1)) { + ptr--; + DCHECK_LE(static_cast<ptrdiff_t>(end_ptr - ptr), 5); + } + + return ptr; +} + // Returns the number of bytes needed to encode the value in unsigned LEB128. static inline uint32_t SignedLeb128Size(int32_t data) { // Like UnsignedLeb128Size(), but we need one bit beyond the highest bit that differs from sign. diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc index 36ebb17f4f..7428e98dbb 100644 --- a/runtime/vdex_file.cc +++ b/runtime/vdex_file.cc @@ -30,6 +30,8 @@ #include "dex/dex_file.h" #include "dex/dex_file_loader.h" #include "dex_to_dex_decompiler.h" +#include "hidden_api_access_flags.h" +#include "leb128.h" #include "quicken_info.h" namespace art { @@ -262,6 +264,18 @@ void VdexFile::UnquickenDexFile(const DexFile& target_dex_file, UnquickenDexFile(target_dex_file, source_dex_file.Begin(), decompile_return_instruction); } +static void UpdateAccessFlags(uint8_t* data, uint32_t new_flag, bool is_method) { + // Go back 1 uleb to start. + data = ReverseSearchUnsignedLeb128(data); + if (is_method) { + // Methods have another uleb field before the access flags + data = ReverseSearchUnsignedLeb128(data); + } + DCHECK_EQ(HiddenApiAccessFlags::RemoveFromDex(DecodeUnsignedLeb128WithoutMovingCursor(data)), + new_flag); + UpdateUnsignedLeb128(data, new_flag); +} + void VdexFile::UnquickenDexFile(const DexFile& target_dex_file, const uint8_t* source_dex_begin, bool decompile_return_instruction) const { @@ -280,27 +294,32 @@ void VdexFile::UnquickenDexFile(const DexFile& target_dex_file, for (ClassDataItemIterator class_it(target_dex_file, class_data); class_it.HasNext(); class_it.Next()) { - if (class_it.IsAtMethod() && class_it.GetMethodCodeItem() != nullptr) { + if (class_it.IsAtMethod()) { const DexFile::CodeItem* code_item = class_it.GetMethodCodeItem(); - if (!unquickened_code_item.emplace(code_item).second) { - // Already unquickened this code item, do not do it again. - continue; - } - ArrayRef<const uint8_t> quicken_data; - if (!quickening_info.empty()) { - const uint32_t quickening_offset = GetQuickeningInfoOffset( - GetQuickenInfoOffsetTable(source_dex_begin, - target_dex_file.NumMethodIds(), - quickening_info), - class_it.GetMemberIndex(), - quickening_info); - quicken_data = GetQuickeningInfoAt(quickening_info, quickening_offset); + if (code_item != nullptr && unquickened_code_item.emplace(code_item).second) { + ArrayRef<const uint8_t> quicken_data; + if (!quickening_info.empty()) { + const uint32_t quickening_offset = GetQuickeningInfoOffset( + GetQuickenInfoOffsetTable(source_dex_begin, + target_dex_file.NumMethodIds(), + quickening_info), + class_it.GetMemberIndex(), + quickening_info); + quicken_data = GetQuickeningInfoAt(quickening_info, quickening_offset); + } + optimizer::ArtDecompileDEX( + target_dex_file, + *code_item, + quicken_data, + decompile_return_instruction); } - optimizer::ArtDecompileDEX( - target_dex_file, - *code_item, - quicken_data, - decompile_return_instruction); + UpdateAccessFlags(const_cast<uint8_t*>(class_it.DataPointer()), + class_it.GetMemberAccessFlags(), + /*is_method*/ true); + } else { + UpdateAccessFlags(const_cast<uint8_t*>(class_it.DataPointer()), + class_it.GetMemberAccessFlags(), + /*is_method*/ false); } } } diff --git a/test/983-source-transform-verify/expected.txt b/test/983-source-transform-verify/expected.txt index abcdf3a868..aa51ea08ae 100644 --- a/test/983-source-transform-verify/expected.txt +++ b/test/983-source-transform-verify/expected.txt @@ -1,2 +1,3 @@ Dex file hook for art/Test983$Transform Dex file hook for java/lang/Object +Dex file hook for java/lang/ClassLoader diff --git a/test/983-source-transform-verify/src/art/Test983.java b/test/983-source-transform-verify/src/art/Test983.java index b81e7f4df3..faae96aef6 100644 --- a/test/983-source-transform-verify/src/art/Test983.java +++ b/test/983-source-transform-verify/src/art/Test983.java @@ -16,7 +16,6 @@ package art; -import java.util.Base64; public class Test983 { static class Transform { public void sayHi() { @@ -29,10 +28,11 @@ public class Test983 { } public static void doTest() { - Transform abc = new Transform(); Redefinition.enableCommonRetransformation(true); Redefinition.doCommonClassRetransformation(Transform.class); Redefinition.doCommonClassRetransformation(Object.class); + // NB java.lang.ClassLoader has hidden fields. + Redefinition.doCommonClassRetransformation(ClassLoader.class); Redefinition.enableCommonRetransformation(false); } } diff --git a/tools/hiddenapi/hiddenapi.cc b/tools/hiddenapi/hiddenapi.cc index a755fdb40b..c893da646d 100644 --- a/tools/hiddenapi/hiddenapi.cc +++ b/tools/hiddenapi/hiddenapi.cc @@ -118,9 +118,11 @@ class DexMember { // until we hit the terminating byte of the previous Leb128 value. const uint8_t* ptr = it_.DataPointer(); if (it_.IsAtMethod()) { - ptr = ReverseSearchUnsignedLeb128(ptr, it_.GetMethodCodeItemOffset()); + ptr = ReverseSearchUnsignedLeb128(ptr); + DCHECK_EQ(DecodeUnsignedLeb128WithoutMovingCursor(ptr), it_.GetMethodCodeItemOffset()); } - ptr = ReverseSearchUnsignedLeb128(ptr, old_flags); + ptr = ReverseSearchUnsignedLeb128(ptr); + DCHECK_EQ(DecodeUnsignedLeb128WithoutMovingCursor(ptr), old_flags); // Overwrite the access flags. UpdateUnsignedLeb128(const_cast<uint8_t*>(ptr), new_flags); @@ -158,38 +160,6 @@ class DexMember { return klass_.GetDexFile().GetFieldId(it_.GetMemberIndex()); } - static inline bool IsLeb128Terminator(const uint8_t* ptr) { - return *ptr <= 0x7f; - } - - // Returns the first byte of a Leb128 value assuming that: - // (1) `end_ptr` points to the first byte after the Leb128 value, and - // (2) there is another Leb128 value before this one. - // The function will fail after reading 5 bytes (the longest supported Leb128 - // encoding) to protect against situations when (2) is not satisfied. - // When a Leb128 value is discovered, it is decoded and CHECKed against `value`. - static const uint8_t* ReverseSearchUnsignedLeb128(const uint8_t* end_ptr, uint32_t expected) { - const uint8_t* ptr = end_ptr; - - // Move one byte back, check that this is the terminating byte. - ptr--; - CHECK(IsLeb128Terminator(ptr)); - - // Keep moving back while the previous byte is not a terminating byte. - // Fail after reading five bytes in case there isn't another Leb128 value - // before this one. - while (!IsLeb128Terminator(ptr - 1)) { - ptr--; - CHECK_LE((size_t) (end_ptr - ptr), 5u); - } - - // Check that the decoded value matches the `expected` value. - const uint8_t* tmp_ptr = ptr; - CHECK_EQ(DecodeUnsignedLeb128(&tmp_ptr), expected); - - return ptr; - } - const DexClass& klass_; const ClassDataItemIterator& it_; }; |