diff options
author | 2018-01-19 18:04:46 -0800 | |
---|---|---|
committer | 2018-01-25 13:12:14 -0800 | |
commit | 754b7575e65f0e0cc8b080b268378daf54881c65 (patch) | |
tree | 335b707c603aebed1db283f8af7f0341ed8d35c0 | |
parent | d78ca5213b780ca3165acb68e44f88f639e8ca45 (diff) |
patchoat: add ability to verify relocated .art files
Patchoat can verify that a relocated .art file hasn't been modified
after generation using the --verify flag.
Test: adb shell /system/bin/patchoat --verify \
--input-image-location=/system/framework/boot.art \
--output-image-file=/data/dalvik-cache/arm64/system@framework@boot.art \
--instruction-set=arm64
Bug: 66697305
Change-Id: If6ea02a0527381c520078cd6f3ae2c275a8a8ab1
-rw-r--r-- | patchoat/patchoat.cc | 277 | ||||
-rw-r--r-- | patchoat/patchoat.h | 4 | ||||
-rw-r--r-- | patchoat/patchoat_test.cc | 219 |
3 files changed, 310 insertions, 190 deletions
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc index 6c9cf864b3..ba09cb3d52 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -25,12 +25,14 @@ #include <string> #include <vector> +#include "android-base/file.h" #include "android-base/stringprintf.h" #include "android-base/strings.h" #include "art_field-inl.h" #include "art_method-inl.h" #include "base/dumpable.h" +#include "base/file_utils.h" #include "base/logging.h" // For InitLogging. #include "base/memory_tool.h" #include "base/scoped_flock.h" @@ -235,6 +237,126 @@ static bool WriteRelFile( return true; } +static bool CheckImageIdenticalToOriginalExceptForRelocation( + const std::string& relocated_filename, + const std::string& original_filename, + std::string* error_msg) { + *error_msg = ""; + std::string rel_filename = original_filename + ".rel"; + std::unique_ptr<File> rel_file(OS::OpenFileForReading(rel_filename.c_str())); + if (rel_file.get() == nullptr) { + *error_msg = StringPrintf("Failed to open image relocation file %s", rel_filename.c_str()); + return false; + } + int64_t rel_size = rel_file->GetLength(); + if (rel_size < 0) { + *error_msg = StringPrintf("Error while getting size of image relocation file %s", + rel_filename.c_str()); + return false; + } + std::unique_ptr<uint8_t[]> rel(new uint8_t[rel_size]); + if (!rel_file->ReadFully(rel.get(), rel_size)) { + *error_msg = StringPrintf("Failed to read image relocation file %s", rel_filename.c_str()); + return false; + } + + std::unique_ptr<File> image_file(OS::OpenFileForReading(relocated_filename.c_str())); + if (image_file.get() == nullptr) { + *error_msg = StringPrintf("Unable to open relocated image file %s", + relocated_filename.c_str()); + return false; + } + + int64_t image_size = image_file->GetLength(); + if (image_size < 0) { + *error_msg = StringPrintf("Error while getting size of relocated image file %s", + relocated_filename.c_str()); + return false; + } + if ((image_size % 4) != 0) { + *error_msg = + StringPrintf( + "Relocated image file %s size not multiple of 4: %jd", + relocated_filename.c_str(), image_size); + return false; + } + if (image_size > UINT32_MAX) { + *error_msg = + StringPrintf( + "Relocated image file %s too large: %jd" , relocated_filename.c_str(), image_size); + return false; + } + + std::unique_ptr<uint8_t[]> image(new uint8_t[image_size]); + if (!image_file->ReadFully(image.get(), image_size)) { + *error_msg = StringPrintf("Failed to read relocated image file %s", relocated_filename.c_str()); + return false; + } + + const uint8_t* original_image_digest = rel.get(); + if (rel_size < SHA256_DIGEST_LENGTH) { + *error_msg = StringPrintf("Malformed image relocation file %s: too short", + rel_filename.c_str()); + return false; + } + + const ImageHeader& image_header = *reinterpret_cast<const ImageHeader*>(image.get()); + off_t expected_diff = image_header.GetPatchDelta(); + + if (expected_diff == 0) { + *error_msg = StringPrintf("Unsuported patch delta of zero in %s", + relocated_filename.c_str()); + return false; + } + + // Relocated image is expected to differ from the original due to relocation. + // Unrelocate the image in memory to compensate. + uint8_t* image_start = image.get(); + const uint8_t* rel_end = &rel[rel_size]; + const uint8_t* rel_ptr = &rel[SHA256_DIGEST_LENGTH]; + // The remaining .rel file consists of offsets at which relocation should've occurred. + // For each offset, we "unrelocate" the image by subtracting the expected relocation + // diff value (as specified in the image header). + // + // Each offset is encoded as a delta/diff relative to the previous offset. With the + // very first offset being encoded relative to offset 0. + // Deltas are encoded using little-endian 7 bits per byte encoding, with all bytes except + // the last one having the highest bit set. + uint32_t offset = 0; + while (rel_ptr != rel_end) { + uint32_t offset_delta = 0; + if (DecodeUnsignedLeb128Checked(&rel_ptr, rel_end, &offset_delta)) { + offset += offset_delta; + uint32_t *image_value = reinterpret_cast<uint32_t*>(image_start + offset); + *image_value -= expected_diff; + } else { + *error_msg = + StringPrintf( + "Malformed image relocation file %s: " + "last byte has it's most significant bit set", + rel_filename.c_str()); + return false; + } + } + + // Image in memory is now supposed to be identical to the original. We + // confirm this by comparing the digest of the in-memory image to the expected + // digest from relocation file. + uint8_t image_digest[SHA256_DIGEST_LENGTH]; + SHA256(image.get(), image_size, image_digest); + if (memcmp(image_digest, original_image_digest, SHA256_DIGEST_LENGTH) != 0) { + *error_msg = + StringPrintf( + "Relocated image %s does not match the original %s after unrelocation", + relocated_filename.c_str(), + original_filename.c_str()); + return false; + } + + // Relocated image is identical to the original, once relocations are taken into account + return true; +} + bool PatchOat::Patch(const std::string& image_location, off_t delta, const std::string& output_image_directory, @@ -475,6 +597,86 @@ bool PatchOat::Patch(const std::string& image_location, return true; } +bool PatchOat::Verify(const std::string& image_location, + const std::string& output_image_directory, + InstructionSet isa, + TimingLogger* timings) { + if (image_location.empty()) { + LOG(ERROR) << "Original image file not provided"; + return false; + } + if (output_image_directory.empty()) { + LOG(ERROR) << "Relocated image directory not provided"; + return false; + } + + TimingLogger::ScopedTiming t("Runtime Setup", timings); + + CHECK_NE(isa, InstructionSet::kNone); + const char* isa_name = GetInstructionSetString(isa); + + // Set up the runtime + RuntimeOptions options; + NoopCompilerCallbacks callbacks; + options.push_back(std::make_pair("compilercallbacks", &callbacks)); + std::string img = "-Ximage:" + image_location; + options.push_back(std::make_pair(img.c_str(), nullptr)); + options.push_back(std::make_pair("imageinstructionset", reinterpret_cast<const void*>(isa_name))); + options.push_back(std::make_pair("-Xno-sig-chain", nullptr)); + if (!Runtime::Create(options, false)) { + LOG(ERROR) << "Unable to initialize runtime"; + return false; + } + std::unique_ptr<Runtime> runtime(Runtime::Current()); + + // Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start, + // give it away now and then switch to a more manageable ScopedObjectAccess. + Thread::Current()->TransitionFromRunnableToSuspended(kNative); + ScopedObjectAccess soa(Thread::Current()); + + t.NewTiming("Image Verification setup"); + std::vector<gc::space::ImageSpace*> spaces = Runtime::Current()->GetHeap()->GetBootImageSpaces(); + + // TODO: Check that no other .rel files exist in the original dir + + bool success = true; + std::string image_location_dir = android::base::Dirname(image_location); + for (size_t i = 0; i < spaces.size(); ++i) { + gc::space::ImageSpace* space = spaces[i]; + std::string image_filename = space->GetImageLocation(); + + std::string relocated_image_filename; + std::string error_msg; + if (!GetDalvikCacheFilename(image_filename.c_str(), + output_image_directory.c_str(), &relocated_image_filename, &error_msg)) { + LOG(ERROR) << "Failed to find relocated image file name: " << error_msg; + success = false; + break; + } + // location: /system/framework/boot.art + // isa: arm64 + // basename: boot.art + // original: /system/framework/arm64/boot.art + // relocation: /system/framework/arm64/boot.art.rel + std::string original_image_filename = GetSystemImageFilename(image_filename.c_str(), isa); + + if (!CheckImageIdenticalToOriginalExceptForRelocation( + relocated_image_filename, original_image_filename, &error_msg)) { + LOG(ERROR) << error_msg; + success = false; + break; + } + } + + if (!kIsDebugBuild && !(RUNNING_ON_MEMORY_TOOL && kMemoryToolDetectsLeaks)) { + // We want to just exit on non-debug builds, not bringing the runtime down + // in an orderly fashion. So release the following fields. + runtime.release(); + } + + return success; +} + bool PatchOat::WriteImage(File* out) { TimingLogger::ScopedTiming t("Writing image File", timings_); std::string error_msg; @@ -919,6 +1121,8 @@ NO_RETURN static void Usage(const char *fmt, ...) { UsageError(" --base-offset-delta=<delta>: Specify the amount to change the old base-offset by."); UsageError(" This value may be negative."); UsageError(""); + UsageError(" --verify: Verify an existing patched file instead of creating one."); + UsageError(""); UsageError(" --dump-timings: dump out patch timing information"); UsageError(""); UsageError(" --no-dump-timings: do not dump out patch timing information"); @@ -927,16 +1131,16 @@ NO_RETURN static void Usage(const char *fmt, ...) { exit(EXIT_FAILURE); } -static int patchoat_image(TimingLogger& timings, - InstructionSet isa, - const std::string& input_image_location, - const std::string& output_image_filename, - const std::string& output_image_relocation_filename, - off_t base_delta, - bool base_delta_set, - bool debug) { +static int patchoat_patch_image(TimingLogger& timings, + InstructionSet isa, + const std::string& input_image_location, + const std::string& output_image_directory, + const std::string& output_image_relocation_filename, + off_t base_delta, + bool base_delta_set, + bool debug) { CHECK(!input_image_location.empty()); - if ((output_image_filename.empty()) && (output_image_relocation_filename.empty())) { + if ((output_image_directory.empty()) && (output_image_relocation_filename.empty())) { Usage("Image patching requires --output-image-file or --output-image-relocation-file"); } @@ -956,8 +1160,6 @@ static int patchoat_image(TimingLogger& timings, TimingLogger::ScopedTiming pt("patch image and oat", &timings); - std::string output_image_directory = - output_image_filename.substr(0, output_image_filename.find_last_of('/')); std::string output_image_relocation_directory = output_image_relocation_filename.substr( 0, output_image_relocation_filename.find_last_of('/')); @@ -976,6 +1178,26 @@ static int patchoat_image(TimingLogger& timings, return ret ? EXIT_SUCCESS : EXIT_FAILURE; } +static int patchoat_verify_image(TimingLogger& timings, + InstructionSet isa, + const std::string& input_image_location, + const std::string& output_image_directory) { + CHECK(!input_image_location.empty()); + TimingLogger::ScopedTiming pt("verify image and oat", &timings); + + bool ret = + PatchOat::Verify( + input_image_location, + output_image_directory, + isa, + &timings); + + if (kIsDebugBuild) { + LOG(INFO) << "Exiting with return ... " << ret; + } + return ret ? EXIT_SUCCESS : EXIT_FAILURE; +} + static int patchoat(int argc, char **argv) { InitLogging(argv, Runtime::Abort); MemMap::Init(); @@ -1003,6 +1225,7 @@ static int patchoat(int argc, char **argv) { off_t base_delta = 0; bool base_delta_set = false; bool dump_timings = kIsDebugBuild; + bool verify = false; for (int i = 0; i < argc; ++i) { const StringPiece option(argv[i]); @@ -1034,24 +1257,40 @@ static int patchoat(int argc, char **argv) { dump_timings = true; } else if (option == "--no-dump-timings") { dump_timings = false; + } else if (option == "--verify") { + verify = true; } else { Usage("Unknown argument %s", option.data()); } } + // TODO: Have calls to patchoat pass in the output_image directory instead of + // the output_image_filename. + std::string output_image_directory; + if (!output_image_filename.empty()) + output_image_directory = android::base::Dirname(output_image_filename); + // The instruction set is mandatory. This simplifies things... if (!isa_set) { Usage("Instruction set must be set."); } - int ret = patchoat_image(timings, - isa, - input_image_location, - output_image_filename, - output_image_relocation_filename, - base_delta, - base_delta_set, - debug); + int ret; + if (verify) { + ret = patchoat_verify_image(timings, + isa, + input_image_location, + output_image_directory); + } else { + ret = patchoat_patch_image(timings, + isa, + input_image_location, + output_image_directory, + output_image_relocation_filename, + base_delta, + base_delta_set, + debug); + } timings.EndTiming(); if (dump_timings) { diff --git a/patchoat/patchoat.h b/patchoat/patchoat.h index 1033a2e5e1..ba59d570a7 100644 --- a/patchoat/patchoat.h +++ b/patchoat/patchoat.h @@ -53,6 +53,10 @@ class PatchOat { const std::string& output_image_relocation_directory, InstructionSet isa, TimingLogger* timings); + static bool Verify(const std::string& image_location, + const std::string& output_image_filename, + InstructionSet isa, + TimingLogger* timings); // Generates a patch which can be used to efficiently relocate the original file or to check that // a relocated file matches the original. The patch is generated from the difference of the diff --git a/patchoat/patchoat_test.cc b/patchoat/patchoat_test.cc index 90cb4f8310..69c6bfae30 100644 --- a/patchoat/patchoat_test.cc +++ b/patchoat/patchoat_test.cc @@ -124,18 +124,36 @@ class PatchoatTest : public DexoptTest { return RunDex2OatOrPatchoat(argv, error_msg); } - bool RelocateBootImage(const std::string& input_image_location, - const std::string& output_image_filename, - off_t base_offset_delta, - std::string* error_msg) { + static std::vector<std::string> BasePatchoatCommand(const std::string& input_image_location, + off_t base_offset_delta) { Runtime* const runtime = Runtime::Current(); std::vector<std::string> argv; argv.push_back(runtime->GetPatchoatExecutable()); argv.push_back("--input-image-location=" + input_image_location); - argv.push_back("--output-image-file=" + output_image_filename); argv.push_back(StringPrintf("--base-offset-delta=0x%jx", (intmax_t) base_offset_delta)); argv.push_back(StringPrintf("--instruction-set=%s", GetInstructionSetString(kRuntimeISA))); + return argv; + } + + bool RelocateBootImage(const std::string& input_image_location, + const std::string& output_image_filename, + off_t base_offset_delta, + std::string* error_msg) { + std::vector<std::string> argv = BasePatchoatCommand(input_image_location, base_offset_delta); + argv.push_back("--output-image-file=" + output_image_filename); + + return RunDex2OatOrPatchoat(argv, error_msg); + } + + bool VerifyBootImage(const std::string& input_image_location, + const std::string& output_image_filename, + off_t base_offset_delta, + std::string* error_msg) { + std::vector<std::string> argv = BasePatchoatCommand(input_image_location, base_offset_delta); + argv.push_back("--output-image-file=" + output_image_filename); + argv.push_back("--verify"); + return RunDex2OatOrPatchoat(argv, error_msg); } @@ -143,13 +161,8 @@ class PatchoatTest : public DexoptTest { const std::string& output_rel_filename, off_t base_offset_delta, std::string* error_msg) { - Runtime* const runtime = Runtime::Current(); - std::vector<std::string> argv; - argv.push_back(runtime->GetPatchoatExecutable()); - argv.push_back("--input-image-location=" + input_image_location); + std::vector<std::string> argv = BasePatchoatCommand(input_image_location, base_offset_delta); argv.push_back("--output-image-relocation-file=" + output_rel_filename); - argv.push_back(StringPrintf("--base-offset-delta=0x%jx", (intmax_t) base_offset_delta)); - argv.push_back(StringPrintf("--instruction-set=%s", GetInstructionSetString(kRuntimeISA))); return RunDex2OatOrPatchoat(argv, error_msg); } @@ -280,34 +293,6 @@ class PatchoatTest : public DexoptTest { } bool BinaryDiff( - const std::string& filename1, - const std::vector<uint8_t>& data1, - const std::string& filename2, - const std::vector<uint8_t>& data2, - std::string* error_msg) { - if (data1.size() != data1.size()) { - *error_msg = - StringPrintf( - "%s and %s are of different size: %zu vs %zu", - filename1.c_str(), - filename2.c_str(), - data1.size(), - data2.size()); - return true; - } - size_t size = data1.size(); - for (size_t i = 0; i < size; i++) { - if (data1[i] != data2[i]) { - *error_msg = - StringPrintf("%s and %s differ at offset %zu", filename1.c_str(), filename2.c_str(), i); - return true; - } - } - - return false; - } - - bool BinaryDiff( const std::string& filename1, const std::string& filename2, std::string* error_msg) { std::string read_error_msg; std::vector<uint8_t> image1; @@ -320,97 +305,26 @@ class PatchoatTest : public DexoptTest { *error_msg = StringPrintf("Failed to read %s: %s", filename2.c_str(), read_error_msg.c_str()); return true; } - return BinaryDiff(filename1, image1, filename2, image2, error_msg); - } - - bool IsImageIdenticalToOriginalExceptForRelocation( - const std::string& relocated_filename, - const std::string& original_filename, - const std::string& rel_filename, - std::string* error_msg) { - *error_msg = ""; - std::string read_error_msg; - std::vector<uint8_t> rel; - if (!ReadFully(rel_filename, &rel, &read_error_msg)) { - *error_msg = - StringPrintf("Failed to read %s: %s", rel_filename.c_str(), read_error_msg.c_str()); - return false; - } - std::vector<uint8_t> relocated; - if (!ReadFully(relocated_filename, &relocated, &read_error_msg)) { - *error_msg = - StringPrintf("Failed to read %s: %s", relocated_filename.c_str(), read_error_msg.c_str()); - return false; - } - - size_t image_size = relocated.size(); - if ((image_size % 4) != 0) { + if (image1.size() != image1.size()) { *error_msg = StringPrintf( - "Relocated image file %s size not multiple of 4: %zu", - relocated_filename.c_str(), image_size); - return false; - } - if (image_size > UINT32_MAX) { - *error_msg = - StringPrintf( - "Relocated image file %s too large: %zu" , relocated_filename.c_str(), image_size); - return false; + "%s and %s are of different size: %zu vs %zu", + filename1.c_str(), + filename2.c_str(), + image1.size(), + image2.size()); + return true; } - - const ImageHeader& relocated_header = *reinterpret_cast<const ImageHeader*>(relocated.data()); - off_t expected_diff = relocated_header.GetPatchDelta(); - - if (expected_diff != 0) { - // Relocated image is expected to differ from the original due to relocation. - // Unrelocate the image in memory to compensate. - uint8_t* image_start = relocated.data(); - const uint8_t* rel_end = &rel[rel.size()]; - if (rel.size() < SHA256_DIGEST_LENGTH) { + size_t size = image1.size(); + for (size_t i = 0; i < size; i++) { + if (image1[i] != image2[i]) { *error_msg = - StringPrintf("Malformed image relocation file %s: too short", rel_filename.c_str()); - return false; - } - const uint8_t* rel_ptr = &rel[SHA256_DIGEST_LENGTH]; - // The remaining .rel file consists of offsets at which relocation should've occurred. - // For each offset, we "unrelocate" the image by subtracting the expected relocation - // diff value (as specified in the image header). - // - // Each offset is encoded as a delta/diff relative to the previous offset. With the - // very first offset being encoded relative to offset 0. - // Deltas are encoded using little-endian 7 bits per byte encoding, with all bytes except - // the last one having the highest bit set. - uint32_t offset = 0; - while (rel_ptr != rel_end) { - uint32_t offset_delta = 0; - if (DecodeUnsignedLeb128Checked(&rel_ptr, rel_end, &offset_delta)) { - offset += offset_delta; - uint32_t *image_value = reinterpret_cast<uint32_t*>(image_start + offset); - *image_value -= expected_diff; - } else { - *error_msg = - StringPrintf( - "Malformed image relocation file %s: " - "last byte has it's most significant bit set", - rel_filename.c_str()); - return false; - } + StringPrintf("%s and %s differ at offset %zu", filename1.c_str(), filename2.c_str(), i); + return true; } } - // Image in memory is now supposed to be identical to the original. Compare it to the original. - std::vector<uint8_t> original; - if (!ReadFully(original_filename, &original, &read_error_msg)) { - *error_msg = - StringPrintf("Failed to read %s: %s", original_filename.c_str(), read_error_msg.c_str()); - return false; - } - if (BinaryDiff(relocated_filename, relocated, original_filename, original, error_msg)) { - return false; - } - - // Relocated image is identical to the original, once relocations are taken into account - return true; + return false; } }; @@ -524,7 +438,7 @@ TEST_F(PatchoatTest, PatchoatRelocationSameAsDex2oatRelocation) { #endif } -TEST_F(PatchoatTest, RelFileSufficientToUnpatch) { +TEST_F(PatchoatTest, RelFileVerification) { // This test checks that a boot image relocated using patchoat can be unrelocated using the .rel // file created by patchoat. @@ -546,10 +460,6 @@ TEST_F(PatchoatTest, RelFileSufficientToUnpatch) { } // Generate image relocation file for the original boot image - ScratchFile rel_scratch; - rel_scratch.Unlink(); - std::string rel_dir = rel_scratch.GetFilename(); - ASSERT_EQ(0, mkdir(rel_dir.c_str(), 0700)); std::string dex2oat_orig_with_arch_dir = dex2oat_orig_dir + "/" + GetInstructionSetString(kRuntimeISA); // The arch-including symlink is needed by patchoat @@ -557,7 +467,7 @@ TEST_F(PatchoatTest, RelFileSufficientToUnpatch) { off_t base_addr_delta = 0x100000; if (!GenerateBootImageRelFile( dex2oat_orig_dir + "/boot.art", - rel_dir + "/boot.art.rel", + dex2oat_orig_dir + "/boot.art.rel", base_addr_delta, &error_msg)) { FAIL() << "RelocateBootImage failed: " << error_msg; @@ -582,8 +492,8 @@ TEST_F(PatchoatTest, RelFileSufficientToUnpatch) { // Assert that patchoat created the same set of .art and .art.rel files std::vector<std::string> rel_basenames; std::vector<std::string> relocated_image_basenames; - if (!ListDirFilesEndingWith(rel_dir, "", &rel_basenames, &error_msg)) { - FAIL() << "Failed to list *.art.rel files in " << rel_dir << ": " << error_msg; + if (!ListDirFilesEndingWith(dex2oat_orig_dir, ".rel", &rel_basenames, &error_msg)) { + FAIL() << "Failed to list *.art.rel files in " << dex2oat_orig_dir << ": " << error_msg; } if (!ListDirFilesEndingWith(relocated_dir, ".art", &relocated_image_basenames, &error_msg)) { FAIL() << "Failed to list *.art files in " << relocated_dir << ": " << error_msg; @@ -611,52 +521,19 @@ TEST_F(PatchoatTest, RelFileSufficientToUnpatch) { } ASSERT_EQ(rel_shortened_basenames, relocated_image_shortened_basenames); - // For each image file, assert that unrelocating the image produces its original version - for (size_t i = 0; i < relocated_image_basenames.size(); i++) { - const std::string& original_image_filename = - dex2oat_orig_dir + "/" + relocated_image_shortened_basenames[i] + ".art"; - const std::string& relocated_image_filename = - relocated_dir + "/" + relocated_image_basenames[i]; - const std::string& rel_filename = rel_dir + "/" + rel_basenames[i]; - - // Assert that relocated image differs from the original - if (!BinaryDiff(original_image_filename, relocated_image_filename, &error_msg)) { - FAIL() << "Relocated image " << relocated_image_filename - << " identical to the original image " << original_image_filename; - } - - // Assert that relocated image is identical to the original except for relocations described in - // the .rel file - if (!IsImageIdenticalToOriginalExceptForRelocation( - relocated_image_filename, original_image_filename, rel_filename, &error_msg)) { - FAIL() << "Unrelocating " << relocated_image_filename << " using " << rel_filename - << " did not produce the same output as " << original_image_filename << ": " << error_msg; - } - - // Assert that the digest of original image in .rel file is as expected - std::vector<uint8_t> original; - if (!ReadFully(original_image_filename, &original, &error_msg)) { - FAIL() << "Failed to read original image " << original_image_filename; - } - std::vector<uint8_t> rel; - if (!ReadFully(rel_filename, &rel, &error_msg)) { - FAIL() << "Failed to read image relocation file " << rel_filename; - } - uint8_t original_image_digest[SHA256_DIGEST_LENGTH]; - SHA256(original.data(), original.size(), original_image_digest); - const uint8_t* original_image_digest_in_rel_file = rel.data(); - if (memcmp(original_image_digest_in_rel_file, original_image_digest, SHA256_DIGEST_LENGTH)) { - FAIL() << "Digest of original image in " << rel_filename << " does not match the original" - " image " << original_image_filename; - } + // Assert that verification works with the .rel files. + if (!VerifyBootImage( + dex2oat_orig_dir + "/boot.art", + relocated_dir + "/boot.art", + base_addr_delta, + &error_msg)) { + FAIL() << "VerifyBootImage failed: " << error_msg; } ClearDirectory(dex2oat_orig_dir.c_str(), /*recursive*/ true); - ClearDirectory(rel_dir.c_str(), /*recursive*/ true); ClearDirectory(relocated_dir.c_str(), /*recursive*/ true); rmdir(dex2oat_orig_dir.c_str()); - rmdir(rel_dir.c_str()); rmdir(relocated_dir.c_str()); } |