diff options
Diffstat (limited to 'patchoat/patchoat.cc')
-rw-r--r-- | patchoat/patchoat.cc | 289 |
1 files changed, 48 insertions, 241 deletions
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc index 6c9cf864b3..eb648cba18 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -15,7 +15,6 @@ */ #include "patchoat.h" -#include <openssl/sha.h> #include <stdio.h> #include <stdlib.h> #include <sys/file.h> @@ -43,7 +42,6 @@ #include "gc/space/image_space.h" #include "image-inl.h" #include "intern_table.h" -#include "leb128.h" #include "mirror/dex_cache.h" #include "mirror/executable.h" #include "mirror/method.h" @@ -60,8 +58,6 @@ namespace art { -using android::base::StringPrintf; - static const OatHeader* GetOatHeader(const ElfFile* elf_file) { uint64_t off = 0; if (!elf_file->GetSectionOffsetAndSize(".rodata", &off, nullptr)) { @@ -124,134 +120,11 @@ static bool SymlinkFile(const std::string& input_filename, const std::string& ou return true; } -bool PatchOat::GeneratePatch( - const MemMap& original, - const MemMap& relocated, - std::vector<uint8_t>* output, - std::string* error_msg) { - // FORMAT of the patch (aka image relocation) file: - // * SHA-256 digest (32 bytes) of original/unrelocated file (e.g., the one from /system) - // * List of monotonically increasing offsets (max value defined by uint32_t) at which relocations - // occur. - // Each element is represented as the delta from the previous offset in the list (first element - // is a delta from 0). Each delta is encoded using unsigned LEB128: little-endian - // variable-length 7 bits per byte encoding, where all bytes have the highest bit (0x80) set - // except for the final byte which does not have that bit set. For example, 0x3f is offset 0x3f, - // whereas 0xbf 0x05 is offset (0x3f & 0x7f) | (0x5 << 7) which is 0x2bf. Most deltas end up - // being encoding using just one byte, achieving ~4x decrease in relocation file size compared - // to the encoding where offsets are stored verbatim, as uint32_t. - - size_t original_size = original.Size(); - size_t relocated_size = relocated.Size(); - if (original_size != relocated_size) { - *error_msg = - StringPrintf( - "Original and relocated image sizes differ: %zu vs %zu", original_size, relocated_size); - return false; - } - if ((original_size % 4) != 0) { - *error_msg = StringPrintf("Image size not multiple of 4: %zu", original_size); - return false; - } - if (original_size > UINT32_MAX) { - *error_msg = StringPrintf("Image too large: %zu" , original_size); - return false; - } - - const ImageHeader& relocated_header = - *reinterpret_cast<const ImageHeader*>(relocated.Begin()); - // Offsets are supposed to differ between original and relocated by this value - off_t expected_diff = relocated_header.GetPatchDelta(); - if (expected_diff == 0) { - // Can't identify offsets which are supposed to differ due to relocation - *error_msg = "Relocation delta is 0"; - return false; - } - - // Output the SHA-256 digest of the original - output->resize(SHA256_DIGEST_LENGTH); - const uint8_t* original_bytes = original.Begin(); - SHA256(original_bytes, original_size, output->data()); - - // Output the list of offsets at which the original and patched images differ - size_t last_diff_offset = 0; - size_t diff_offset_count = 0; - const uint8_t* relocated_bytes = relocated.Begin(); - for (size_t offset = 0; offset < original_size; offset += 4) { - uint32_t original_value = *reinterpret_cast<const uint32_t*>(original_bytes + offset); - uint32_t relocated_value = *reinterpret_cast<const uint32_t*>(relocated_bytes + offset); - off_t diff = relocated_value - original_value; - if (diff == 0) { - continue; - } else if (diff != expected_diff) { - *error_msg = - StringPrintf( - "Unexpected diff at offset %zu. Expected: %jd, but was: %jd", - offset, - (intmax_t) expected_diff, - (intmax_t) diff); - return false; - } - - uint32_t offset_diff = offset - last_diff_offset; - last_diff_offset = offset; - diff_offset_count++; - - EncodeUnsignedLeb128(output, offset_diff); - } - - if (diff_offset_count == 0) { - *error_msg = "Original and patched images are identical"; - return false; - } - - return true; -} - -static bool WriteRelFile( - const MemMap& original, - const MemMap& relocated, - const std::string& rel_filename, - std::string* error_msg) { - std::vector<uint8_t> output; - if (!PatchOat::GeneratePatch(original, relocated, &output, error_msg)) { - return false; - } - - std::unique_ptr<File> rel_file(OS::CreateEmptyFileWriteOnly(rel_filename.c_str())); - if (rel_file.get() == nullptr) { - *error_msg = StringPrintf("Failed to create/open output file %s", rel_filename.c_str()); - return false; - } - if (!rel_file->WriteFully(output.data(), output.size())) { - *error_msg = StringPrintf("Failed to write to %s", rel_filename.c_str()); - return false; - } - if (rel_file->FlushCloseOrErase() != 0) { - *error_msg = StringPrintf("Failed to flush and close %s", rel_filename.c_str()); - return false; - } - - return true; -} - bool PatchOat::Patch(const std::string& image_location, off_t delta, - const std::string& output_image_directory, - const std::string& output_image_relocation_directory, + const std::string& output_directory, InstructionSet isa, TimingLogger* timings) { - bool output_image = !output_image_directory.empty(); - bool output_image_relocation = !output_image_relocation_directory.empty(); - if ((!output_image) && (!output_image_relocation)) { - // Nothing to do - return true; - } - if ((output_image_relocation) && (delta == 0)) { - LOG(ERROR) << "Cannot output image relocation information when requested relocation delta is 0"; - return false; - } - CHECK(Runtime::Current() == nullptr); CHECK(!image_location.empty()) << "image file must have a filename."; @@ -348,35 +221,32 @@ bool PatchOat::Patch(const std::string& image_location, return false; } - if (output_image) { - MaybePic is_oat_pic = IsOatPic(elf.get()); - if (is_oat_pic >= ERROR_FIRST) { - // Error logged by IsOatPic - return false; - } else if (is_oat_pic == NOT_PIC) { - LOG(ERROR) << "patchoat cannot be used on non-PIC oat file: " << input_oat_file->GetPath(); + MaybePic is_oat_pic = IsOatPic(elf.get()); + if (is_oat_pic >= ERROR_FIRST) { + // Error logged by IsOatPic + return false; + } else if (is_oat_pic == NOT_PIC) { + LOG(ERROR) << "patchoat cannot be used on non-PIC oat file: " << input_oat_file->GetPath(); + return false; + } else { + CHECK(is_oat_pic == PIC); + + // Create a symlink. + std::string converted_image_filename = space->GetImageLocation(); + std::replace(converted_image_filename.begin() + 1, converted_image_filename.end(), '/', '@'); + std::string output_image_filename = output_directory + + (android::base::StartsWith(converted_image_filename, "/") ? "" : "/") + + converted_image_filename; + std::string output_vdex_filename = + ImageHeader::GetVdexLocationFromImageLocation(output_image_filename); + std::string output_oat_filename = + ImageHeader::GetOatLocationFromImageLocation(output_image_filename); + + if (!ReplaceOatFileWithSymlink(input_oat_file->GetPath(), + output_oat_filename) || + !SymlinkFile(input_vdex_filename, output_vdex_filename)) { + // Errors already logged by above call. return false; - } else { - CHECK(is_oat_pic == PIC); - - // Create a symlink. - std::string converted_image_filename = space->GetImageLocation(); - std::replace( - converted_image_filename.begin() + 1, converted_image_filename.end(), '/', '@'); - std::string output_image_filename = output_image_directory + - (android::base::StartsWith(converted_image_filename, "/") ? "" : "/") + - converted_image_filename; - std::string output_vdex_filename = - ImageHeader::GetVdexLocationFromImageLocation(output_image_filename); - std::string output_oat_filename = - ImageHeader::GetOatLocationFromImageLocation(output_image_filename); - - if (!ReplaceOatFileWithSymlink(input_oat_file->GetPath(), - output_oat_filename) || - !SymlinkFile(input_vdex_filename, output_vdex_filename)) { - // Errors already logged by above call. - return false; - } } } @@ -397,72 +267,28 @@ bool PatchOat::Patch(const std::string& image_location, } } - if (output_image) { - // Write the patched image spaces. - for (size_t i = 0; i < spaces.size(); ++i) { - gc::space::ImageSpace* space = spaces[i]; - - t.NewTiming("Writing image"); - std::string converted_image_filename = space->GetImageLocation(); - std::replace(converted_image_filename.begin() + 1, converted_image_filename.end(), '/', '@'); - std::string output_image_filename = output_image_directory + - (android::base::StartsWith(converted_image_filename, "/") ? "" : "/") + - converted_image_filename; - std::unique_ptr<File> output_image_file(CreateOrOpen(output_image_filename.c_str())); - if (output_image_file.get() == nullptr) { - LOG(ERROR) << "Failed to open output image file at " << output_image_filename; - return false; - } - - PatchOat& p = space_to_patchoat_map.find(space)->second; + // Write the patched image spaces. + for (size_t i = 0; i < spaces.size(); ++i) { + gc::space::ImageSpace* space = spaces[i]; - bool success = p.WriteImage(output_image_file.get()); - success = FinishFile(output_image_file.get(), success); - if (!success) { - return false; - } + t.NewTiming("Writing image"); + std::string converted_image_filename = space->GetImageLocation(); + std::replace(converted_image_filename.begin() + 1, converted_image_filename.end(), '/', '@'); + std::string output_image_filename = output_directory + + (android::base::StartsWith(converted_image_filename, "/") ? "" : "/") + + converted_image_filename; + std::unique_ptr<File> output_image_file(CreateOrOpen(output_image_filename.c_str())); + if (output_image_file.get() == nullptr) { + LOG(ERROR) << "Failed to open output image file at " << output_image_filename; + return false; } - } - if (output_image_relocation) { - // Write the image relocation information for each space. - for (size_t i = 0; i < spaces.size(); ++i) { - gc::space::ImageSpace* space = spaces[i]; - - t.NewTiming("Writing image relocation"); - std::string original_image_filename(space->GetImageLocation() + ".rel"); - std::string image_relocation_filename = - output_image_relocation_directory - + (android::base::StartsWith(original_image_filename, "/") ? "" : "/") - + original_image_filename.substr(original_image_filename.find_last_of("/")); - File& input_image = *space_to_file_map.find(space)->second; - int64_t input_image_size = input_image.GetLength(); - if (input_image_size < 0) { - LOG(ERROR) << "Error while getting input image size"; - return false; - } - std::string error_msg; - std::unique_ptr<MemMap> original(MemMap::MapFile(input_image_size, - PROT_READ, - MAP_PRIVATE, - input_image.Fd(), - 0, - /*low_4gb*/false, - input_image.GetPath().c_str(), - &error_msg)); - if (original.get() == nullptr) { - LOG(ERROR) << "Unable to map image file " << input_image.GetPath() << " : " << error_msg; - return false; - } - - PatchOat& p = space_to_patchoat_map.find(space)->second; - const MemMap* relocated = p.image_; + PatchOat& p = space_to_patchoat_map.find(space)->second; - if (!WriteRelFile(*original, *relocated, image_relocation_filename, &error_msg)) { - LOG(ERROR) << "Failed to create image relocation file " << image_relocation_filename - << ": " << error_msg; - return false; - } + bool success = p.WriteImage(output_image_file.get()); + success = FinishFile(output_image_file.get(), success); + if (!success) { + return false; } } @@ -913,9 +739,6 @@ NO_RETURN static void Usage(const char *fmt, ...) { UsageError(" --output-image-file=<file.art>: Specifies the exact file to write the patched"); UsageError(" image file to."); UsageError(""); - UsageError(" --output-image-relocation-file=<file.art.rel>: Specifies the exact file to write"); - UsageError(" the image relocation information to."); - UsageError(""); UsageError(" --base-offset-delta=<delta>: Specify the amount to change the old base-offset by."); UsageError(" This value may be negative."); UsageError(""); @@ -931,13 +754,12 @@ 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) { CHECK(!input_image_location.empty()); - if ((output_image_filename.empty()) && (output_image_relocation_filename.empty())) { - Usage("Image patching requires --output-image-file or --output-image-relocation-file"); + if (output_image_filename.empty()) { + Usage("Image patching requires --output-image-file"); } if (!base_delta_set) { @@ -956,19 +778,9 @@ static int patchoat_image(TimingLogger& timings, TimingLogger::ScopedTiming pt("patch image and oat", &timings); - std::string output_image_directory = + std::string output_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('/')); - bool ret = - PatchOat::Patch( - input_image_location, - base_delta, - output_image_directory, - output_image_relocation_directory, - isa, - &timings); + bool ret = PatchOat::Patch(input_image_location, base_delta, output_directory, isa, &timings); if (kIsDebugBuild) { LOG(INFO) << "Exiting with return ... " << ret; @@ -999,7 +811,6 @@ static int patchoat(int argc, char **argv) { InstructionSet isa = InstructionSet::kNone; std::string input_image_location; std::string output_image_filename; - std::string output_image_relocation_filename; off_t base_delta = 0; bool base_delta_set = false; bool dump_timings = kIsDebugBuild; @@ -1021,9 +832,6 @@ static int patchoat(int argc, char **argv) { input_image_location = option.substr(strlen("--input-image-location=")).data(); } else if (option.starts_with("--output-image-file=")) { output_image_filename = option.substr(strlen("--output-image-file=")).data(); - } else if (option.starts_with("--output-image-relocation-file=")) { - output_image_relocation_filename = - option.substr(strlen("--output-image-relocation-file=")).data(); } else if (option.starts_with("--base-offset-delta=")) { const char* base_delta_str = option.substr(strlen("--base-offset-delta=")).data(); base_delta_set = true; @@ -1048,7 +856,6 @@ static int patchoat(int argc, char **argv) { isa, input_image_location, output_image_filename, - output_image_relocation_filename, base_delta, base_delta_set, debug); |