From a7b9a4660c18a88413280c84c03917ae953d62b0 Mon Sep 17 00:00:00 2001 From: Jed Estep Date: Tue, 15 Dec 2015 16:04:53 -0800 Subject: IO fault injection for OTA packages Bug: 25951086 Change-Id: I31c74c735eb7a975b7f41fe2b2eff042e5699c0c (cherry-picked from commit f1fc48c6e62cfee42d25ad12f443e22d50c15d0b) --- applypatch/applypatch.cpp | 53 ++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 26 deletions(-) (limited to 'applypatch/applypatch.cpp') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 75d77372e..4eec33256 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -35,6 +35,7 @@ #include "mtdutils/mtdutils.h" #include "edify/expr.h" #include "print_sha1.h" +#include "otafault/ota_io.h" static int LoadPartitionContents(const char* filename, FileContents* file); static ssize_t FileSink(const unsigned char* data, ssize_t len, void* token); @@ -79,19 +80,19 @@ int LoadFileContents(const char* filename, FileContents* file) { return -1; } - FILE* f = fopen(filename, "rb"); + FILE* f = ota_fopen(filename, "rb"); if (f == NULL) { printf("failed to open \"%s\": %s\n", filename, strerror(errno)); return -1; } - size_t bytes_read = fread(data.get(), 1, file->size, f); + size_t bytes_read = ota_fread(data.get(), 1, file->size, f); if (bytes_read != static_cast(file->size)) { printf("short read of \"%s\" (%zu bytes of %zd)\n", filename, bytes_read, file->size); - fclose(f); + ota_fclose(f); return -1; } - fclose(f); + ota_fclose(f); file->data = data.release(); SHA1(file->data, file->size, file->sha1); return 0; @@ -180,7 +181,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { } case EMMC: - dev = fopen(partition, "rb"); + dev = ota_fopen(partition, "rb"); if (dev == NULL) { printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno)); return -1; @@ -209,7 +210,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { break; case EMMC: - read = fread(p, 1, next, dev); + read = ota_fread(p, 1, next, dev); break; } if (next != read) { @@ -255,7 +256,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { break; case EMMC: - fclose(dev); + ota_fclose(dev); break; } @@ -282,7 +283,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { // Save the contents of the given FileContents object under the given // filename. Return 0 on success. int SaveFileContents(const char* filename, const FileContents* file) { - int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR); + int fd = ota_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR); if (fd < 0) { printf("failed to open \"%s\" for write: %s\n", filename, strerror(errno)); return -1; @@ -292,14 +293,14 @@ int SaveFileContents(const char* filename, const FileContents* file) { if (bytes_written != file->size) { printf("short write of \"%s\" (%zd bytes of %zd) (%s)\n", filename, bytes_written, file->size, strerror(errno)); - close(fd); + ota_close(fd); return -1; } - if (fsync(fd) != 0) { + if (ota_fsync(fd) != 0) { printf("fsync of \"%s\" failed: %s\n", filename, strerror(errno)); return -1; } - if (close(fd) != 0) { + if (ota_close(fd) != 0) { printf("close of \"%s\" failed: %s\n", filename, strerror(errno)); return -1; } @@ -382,7 +383,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) case EMMC: { size_t start = 0; bool success = false; - int fd = open(partition, O_RDWR | O_SYNC); + int fd = ota_open(partition, O_RDWR | O_SYNC); if (fd < 0) { printf("failed to open %s: %s\n", partition, strerror(errno)); return -1; @@ -397,22 +398,22 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) size_t to_write = len - start; if (to_write > 1<<20) to_write = 1<<20; - ssize_t written = TEMP_FAILURE_RETRY(write(fd, data+start, to_write)); + ssize_t written = TEMP_FAILURE_RETRY(ota_write(fd, data+start, to_write)); if (written == -1) { printf("failed write writing to %s: %s\n", partition, strerror(errno)); return -1; } start += written; } - if (fsync(fd) != 0) { + if (ota_fsync(fd) != 0) { printf("failed to sync to %s (%s)\n", partition, strerror(errno)); return -1; } - if (close(fd) != 0) { + if (ota_close(fd) != 0) { printf("failed to close %s (%s)\n", partition, strerror(errno)); return -1; } - fd = open(partition, O_RDONLY); + fd = ota_open(partition, O_RDONLY); if (fd < 0) { printf("failed to reopen %s for verify (%s)\n", partition, strerror(errno)); return -1; @@ -421,13 +422,13 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) // Drop caches so our subsequent verification read // won't just be reading the cache. sync(); - int dc = open("/proc/sys/vm/drop_caches", O_WRONLY); - if (TEMP_FAILURE_RETRY(write(dc, "3\n", 2)) == -1) { + int dc = ota_open("/proc/sys/vm/drop_caches", O_WRONLY); + if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) { printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno)); } else { printf(" caches dropped\n"); } - close(dc); + ota_close(dc); sleep(1); // verify @@ -447,7 +448,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) size_t so_far = 0; while (so_far < to_read) { ssize_t read_count = - TEMP_FAILURE_RETRY(read(fd, buffer+so_far, to_read-so_far)); + TEMP_FAILURE_RETRY(ota_read(fd, buffer+so_far, to_read-so_far)); if (read_count == -1) { printf("verify read error %s at %zu: %s\n", partition, p, strerror(errno)); @@ -479,7 +480,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) return -1; } - if (close(fd) != 0) { + if (ota_close(fd) != 0) { printf("error closing %s (%s)\n", partition, strerror(errno)); return -1; } @@ -589,7 +590,7 @@ ssize_t FileSink(const unsigned char* data, ssize_t len, void* token) { ssize_t done = 0; ssize_t wrote; while (done < len) { - wrote = TEMP_FAILURE_RETRY(write(fd, data+done, len-done)); + wrote = TEMP_FAILURE_RETRY(ota_write(fd, data+done, len-done)); if (wrote == -1) { printf("error writing %zd bytes: %s\n", (len-done), strerror(errno)); return done; @@ -934,8 +935,8 @@ static int GenerateTarget(FileContents* source_file, token = &memory_sink_str; } else { // We write the decoded output to ".patch". - output_fd = open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, - S_IRUSR | S_IWUSR); + output_fd = ota_open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, + S_IRUSR | S_IWUSR); if (output_fd < 0) { printf("failed to open output file %s: %s\n", tmp_target_filename.c_str(), strerror(errno)); @@ -958,12 +959,12 @@ static int GenerateTarget(FileContents* source_file, } if (!target_is_partition) { - if (fsync(output_fd) != 0) { + if (ota_fsync(output_fd) != 0) { printf("failed to fsync file \"%s\" (%s)\n", tmp_target_filename.c_str(), strerror(errno)); result = 1; } - if (close(output_fd) != 0) { + if (ota_close(output_fd) != 0) { printf("failed to close file \"%s\" (%s)\n", tmp_target_filename.c_str(), strerror(errno)); result = 1; -- cgit v1.2.3 From d6c93afcc28cc65217ba65eeb646009c4f15a2ad Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Wed, 10 Feb 2016 16:41:10 -0800 Subject: applypatch: use vector to store data in FileContents. Bug: 26906416 Change-Id: Ib53b445cd415a1ed5e95733fbc4073f9ef4dbc43 --- applypatch/applypatch.cpp | 103 ++++++++++++++-------------------------------- 1 file changed, 32 insertions(+), 71 deletions(-) (limited to 'applypatch/applypatch.cpp') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 4eec33256..f66dbe3bf 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -56,8 +56,6 @@ static bool mtd_partitions_scanned = false; // // Return 0 on success. int LoadFileContents(const char* filename, FileContents* file) { - file->data = NULL; - // A special 'filename' beginning with "MTD:" or "EMMC:" means to // load the contents of a partition. if (strncmp(filename, "MTD:", 4) == 0 || @@ -70,31 +68,22 @@ int LoadFileContents(const char* filename, FileContents* file) { return -1; } - file->size = file->st.st_size; - file->data = nullptr; - - std::unique_ptr data( - static_cast(malloc(file->size)), free); - if (data == nullptr) { - printf("failed to allocate memory: %s\n", strerror(errno)); - return -1; - } - + std::vector data(file->st.st_size); FILE* f = ota_fopen(filename, "rb"); if (f == NULL) { printf("failed to open \"%s\": %s\n", filename, strerror(errno)); return -1; } - size_t bytes_read = ota_fread(data.get(), 1, file->size, f); - if (bytes_read != static_cast(file->size)) { - printf("short read of \"%s\" (%zu bytes of %zd)\n", filename, bytes_read, file->size); + size_t bytes_read = ota_fread(data.data(), 1, data.size(), f); + if (bytes_read != data.size()) { + printf("short read of \"%s\" (%zu bytes of %zu)\n", filename, bytes_read, data.size()); ota_fclose(f); return -1; } ota_fclose(f); - file->data = data.release(); - SHA1(file->data, file->size, file->sha1); + file->data = std::move(data); + SHA1(file->data.data(), file->data.size(), file->sha1); return 0; } @@ -193,17 +182,17 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { uint8_t parsed_sha[SHA_DIGEST_LENGTH]; // Allocate enough memory to hold the largest size. - file->data = static_cast(malloc(size[index[pairs-1]])); - char* p = (char*)file->data; - file->size = 0; // # bytes read so far + std::vector data(size[index[pairs-1]]); + char* p = reinterpret_cast(data.data()); + size_t data_size = 0; // # bytes read so far bool found = false; for (size_t i = 0; i < pairs; ++i) { // Read enough additional bytes to get us up to the next size. (Again, // we're trying the possibilities in order of increasing size). - size_t next = size[index[i]] - file->size; - size_t read = 0; + size_t next = size[index[i]] - data_size; if (next > 0) { + size_t read = 0; switch (type) { case MTD: read = mtd_read_data(ctx, p, next); @@ -216,12 +205,11 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { if (next != read) { printf("short read (%zu bytes of %zu) for partition \"%s\"\n", read, next, partition); - free(file->data); - file->data = NULL; return -1; } SHA1_Update(&sha_ctx, p, read); - file->size += read; + data_size += read; + p += read; } // Duplicate the SHA context and finalize the duplicate so we can @@ -233,8 +221,6 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { if (ParseSha1(sha1sum[index[i]].c_str(), parsed_sha) != 0) { printf("failed to parse sha1 %s in %s\n", sha1sum[index[i]].c_str(), filename); - free(file->data); - file->data = NULL; return -1; } @@ -246,8 +232,6 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { found = true; break; } - - p += read; } switch (type) { @@ -264,13 +248,13 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { if (!found) { // Ran off the end of the list of (size,sha1) pairs without finding a match. printf("contents of partition \"%s\" didn't match %s\n", partition, filename); - free(file->data); - file->data = NULL; return -1; } SHA1_Final(file->sha1, &sha_ctx); + data.resize(data_size); + file->data = std::move(data); // Fake some stat() info. file->st.st_mode = 0644; file->st.st_uid = 0; @@ -289,10 +273,10 @@ int SaveFileContents(const char* filename, const FileContents* file) { return -1; } - ssize_t bytes_written = FileSink(file->data, file->size, &fd); - if (bytes_written != file->size) { - printf("short write of \"%s\" (%zd bytes of %zd) (%s)\n", - filename, bytes_written, file->size, strerror(errno)); + ssize_t bytes_written = FileSink(file->data.data(), file->data.size(), &fd); + if (bytes_written != static_cast(file->data.size())) { + printf("short write of \"%s\" (%zd bytes of %zu) (%s)\n", + filename, bytes_written, file->data.size(), strerror(errno)); ota_close(fd); return -1; } @@ -543,7 +527,6 @@ int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str, int applypatch_check(const char* filename, int num_patches, char** const patch_sha1_str) { FileContents file; - file.data = NULL; // It's okay to specify no sha1s; the check will pass if the // LoadFileContents is successful. (Useful for reading @@ -555,9 +538,6 @@ int applypatch_check(const char* filename, int num_patches, printf("file \"%s\" doesn't have any of expected " "sha1 sums; checking cache\n", filename); - free(file.data); - file.data = NULL; - // If the source file is missing or corrupted, it might be because // we were killed in the middle of patching it. A copy of it // should have been made in CACHE_TEMP_SOURCE. If that file @@ -571,12 +551,9 @@ int applypatch_check(const char* filename, int num_patches, if (FindMatchingPatch(file.sha1, patch_sha1_str, num_patches) < 0) { printf("cache bits don't match any sha1 for \"%s\"\n", filename); - free(file.data); return 1; } } - - free(file.data); return 0; } @@ -674,8 +651,6 @@ int applypatch(const char* source_filename, FileContents copy_file; FileContents source_file; - copy_file.data = NULL; - source_file.data = NULL; const Value* source_patch_value = NULL; const Value* copy_patch_value = NULL; @@ -685,22 +660,20 @@ int applypatch(const char* source_filename, // The early-exit case: the patch was already applied, this file // has the desired hash, nothing for us to do. printf("already %s\n", short_sha1(target_sha1).c_str()); - free(source_file.data); return 0; } } - if (source_file.data == NULL || + if (source_file.data.empty() || (target_filename != source_filename && strcmp(target_filename, source_filename) != 0)) { // Need to load the source file: either we failed to load the // target file, or we did but it's different from the source file. - free(source_file.data); - source_file.data = NULL; + source_file.data.clear(); LoadFileContents(source_filename, &source_file); } - if (source_file.data != NULL) { + if (!source_file.data.empty()) { int to_use = FindMatchingPatch(source_file.sha1, patch_sha1_str, num_patches); if (to_use >= 0) { source_patch_value = patch_data[to_use]; @@ -708,8 +681,7 @@ int applypatch(const char* source_filename, } if (source_patch_value == NULL) { - free(source_file.data); - source_file.data = NULL; + source_file.data.clear(); printf("source file is bad; trying copy\n"); if (LoadFileContents(CACHE_TEMP_SOURCE, ©_file) < 0) { @@ -726,19 +698,14 @@ int applypatch(const char* source_filename, if (copy_patch_value == NULL) { // fail. printf("copy file doesn't match source SHA-1s either\n"); - free(copy_file.data); return 1; } } - int result = GenerateTarget(&source_file, source_patch_value, - ©_file, copy_patch_value, - source_filename, target_filename, - target_sha1, target_size, bonus_data); - free(source_file.data); - free(copy_file.data); - - return result; + return GenerateTarget(&source_file, source_patch_value, + ©_file, copy_patch_value, + source_filename, target_filename, + target_sha1, target_size, bonus_data); } /* @@ -759,7 +726,6 @@ int applypatch_flash(const char* source_filename, const char* target_filename, } FileContents source_file; - source_file.data = NULL; std::string target_str(target_filename); std::vector pieces = android::base::Split(target_str, ":"); @@ -777,7 +743,6 @@ int applypatch_flash(const char* source_filename, const char* target_filename, // The early-exit case: the image was already applied, this partition // has the desired hash, nothing for us to do. printf("already %s\n", short_sha1(target_sha1).c_str()); - free(source_file.data); return 0; } @@ -787,18 +752,14 @@ int applypatch_flash(const char* source_filename, const char* target_filename, printf("source \"%s\" doesn't have expected sha1 sum\n", source_filename); printf("expected: %s, found: %s\n", short_sha1(target_sha1).c_str(), short_sha1(source_file.sha1).c_str()); - free(source_file.data); return 1; } } - if (WriteToPartition(source_file.data, target_size, target_filename) != 0) { + if (WriteToPartition(source_file.data.data(), target_size, target_filename) != 0) { printf("write of copied data to %s failed\n", target_filename); - free(source_file.data); return 1; } - - free(source_file.data); return 0; } @@ -867,7 +828,7 @@ static int GenerateTarget(FileContents* source_file, // We still write the original source to cache, in case // the partition write is interrupted. - if (MakeFreeSpaceOnCache(source_file->size) < 0) { + if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) { printf("not enough free space on /cache\n"); return 1; } @@ -908,7 +869,7 @@ static int GenerateTarget(FileContents* source_file, return 1; } - if (MakeFreeSpaceOnCache(source_file->size) < 0) { + if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) { printf("not enough free space on /cache\n"); return 1; } @@ -951,10 +912,10 @@ static int GenerateTarget(FileContents* source_file, int result; if (use_bsdiff) { - result = ApplyBSDiffPatch(source_to_use->data, source_to_use->size, + result = ApplyBSDiffPatch(source_to_use->data.data(), source_to_use->data.size(), patch, 0, sink, token, &ctx); } else { - result = ApplyImagePatch(source_to_use->data, source_to_use->size, + result = ApplyImagePatch(source_to_use->data.data(), source_to_use->data.size(), patch, sink, token, &ctx, bonus_data); } -- cgit v1.2.3 From 39c1b5e8722dbf0bbb3ee45e201373099f075345 Mon Sep 17 00:00:00 2001 From: Jed Estep Date: Tue, 15 Dec 2015 16:04:53 -0800 Subject: Control fault injection with config files instead of build flags Bug: 26570379 Change-Id: I76109d09276d6e3ed3a32b6fedafb2582f545c0c (cherry picked from commit d940887dde23597dc358b16d96ca48dd7480fee6) --- applypatch/applypatch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'applypatch/applypatch.cpp') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index f66dbe3bf..644515997 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -34,8 +34,8 @@ #include "applypatch.h" #include "mtdutils/mtdutils.h" #include "edify/expr.h" +#include "ota_io.h" #include "print_sha1.h" -#include "otafault/ota_io.h" static int LoadPartitionContents(const char* filename, FileContents* file); static ssize_t FileSink(const unsigned char* data, ssize_t len, void* token); -- cgit v1.2.3 From d80a99883d5ae2b117c54f076fe1df7eae86d2f8 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 3 Mar 2016 11:43:47 -0800 Subject: Fix the improper use of LOCAL_WHOLE_STATIC_LIBRARIES. If two libraries both use LOCAL_WHOLE_STATIC_LIBRARIES and include a same library, there would be linking errors when generating a shared library (or executable) that depends on the two libraries both. Also clean up Android.mk files. Remove the "LOCAL_MODULE_TAGS := eng" line for the updater module. The module will then default to "optional" which won't be built until needed. Change-Id: I3ec227109b8aa744b7568e7f82f575aae3fe0e6f --- applypatch/applypatch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'applypatch/applypatch.cpp') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 644515997..c8594c283 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -31,7 +31,7 @@ #include #include "openssl/sha.h" -#include "applypatch.h" +#include "applypatch/applypatch.h" #include "mtdutils/mtdutils.h" #include "edify/expr.h" #include "ota_io.h" -- cgit v1.2.3 From 54a2747ef305c10d07d8db393125dbcbb461c428 Mon Sep 17 00:00:00 2001 From: Chih-Hung Hsieh Date: Mon, 18 Apr 2016 11:30:55 -0700 Subject: Fix google-runtime-int warnings. Bug: 28220065 Change-Id: Ida199c66692a1638be6990d583d2ed42583fb592 --- applypatch/applypatch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'applypatch/applypatch.cpp') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index c8594c283..270fde5c4 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -596,7 +596,7 @@ size_t FreeSpaceForFile(const char* filename) { int CacheSizeCheck(size_t bytes) { if (MakeFreeSpaceOnCache(bytes) < 0) { - printf("unable to make %ld bytes available on /cache\n", (long)bytes); + printf("unable to make %zu bytes available on /cache\n", bytes); return 1; } else { return 0; -- cgit v1.2.3 From 63a319201fc0f5c34c1c62b446527e06f57f8d40 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 9 Jun 2016 17:41:22 -0700 Subject: Remove obsolete MTD support. Bug: http://b/29250988 Change-Id: Ia97ba9082a165c37f74d6e1c3f71a367adc59945 --- applypatch/applypatch.cpp | 308 +++++++++++++++------------------------------- 1 file changed, 101 insertions(+), 207 deletions(-) (limited to 'applypatch/applypatch.cpp') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 270fde5c4..02a3c6e41 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -32,7 +32,6 @@ #include "openssl/sha.h" #include "applypatch/applypatch.h" -#include "mtdutils/mtdutils.h" #include "edify/expr.h" #include "ota_io.h" #include "print_sha1.h" @@ -49,17 +48,14 @@ static int GenerateTarget(FileContents* source_file, size_t target_size, const Value* bonus_data); -static bool mtd_partitions_scanned = false; - // Read a file into memory; store the file contents and associated // metadata in *file. // // Return 0 on success. int LoadFileContents(const char* filename, FileContents* file) { - // A special 'filename' beginning with "MTD:" or "EMMC:" means to + // A special 'filename' beginning with "EMMC:" means to // load the contents of a partition. - if (strncmp(filename, "MTD:", 4) == 0 || - strncmp(filename, "EMMC:", 5) == 0) { + if (strncmp(filename, "EMMC:", 5) == 0) { return LoadPartitionContents(filename, file); } @@ -87,10 +83,9 @@ int LoadFileContents(const char* filename, FileContents* file) { return 0; } -// Load the contents of an MTD or EMMC partition into the provided +// Load the contents of an EMMC partition into the provided // FileContents. filename should be a string of the form -// "MTD::::::..." (or -// "EMMC::..."). The smallest size_n bytes for +// "EMMC::...". The smallest size_n bytes for // which that prefix of the partition contents has the corresponding // sha1 hash will be loaded. It is acceptable for a size value to be // repeated with different sha1s. Will return 0 on success. @@ -102,8 +97,6 @@ int LoadFileContents(const char* filename, FileContents* file) { // "end-of-file" marker), so the caller must specify the possible // lengths and the hash of the data, and we'll do the load expecting // to find one of those hashes. -enum PartitionType { MTD, EMMC }; - static int LoadPartitionContents(const char* filename, FileContents* file) { std::string copy(filename); std::vector pieces = android::base::Split(copy, ":"); @@ -112,12 +105,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { return -1; } - enum PartitionType type; - if (pieces[0] == "MTD") { - type = MTD; - } else if (pieces[0] == "EMMC") { - type = EMMC; - } else { + if (pieces[0] != "EMMC") { printf("LoadPartitionContents called with bad filename (%s)\n", filename); return -1; } @@ -145,36 +133,10 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { } ); - MtdReadContext* ctx = NULL; - FILE* dev = NULL; - - switch (type) { - case MTD: { - if (!mtd_partitions_scanned) { - mtd_scan_partitions(); - mtd_partitions_scanned = true; - } - - const MtdPartition* mtd = mtd_find_partition_by_name(partition); - if (mtd == NULL) { - printf("mtd partition \"%s\" not found (loading %s)\n", partition, filename); - return -1; - } - - ctx = mtd_read_partition(mtd); - if (ctx == NULL) { - printf("failed to initialize read of mtd partition \"%s\"\n", partition); - return -1; - } - break; - } - - case EMMC: - dev = ota_fopen(partition, "rb"); - if (dev == NULL) { - printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno)); - return -1; - } + FILE* dev = ota_fopen(partition, "rb"); + if (dev == NULL) { + printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno)); + return -1; } SHA_CTX sha_ctx; @@ -192,16 +154,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { // we're trying the possibilities in order of increasing size). size_t next = size[index[i]] - data_size; if (next > 0) { - size_t read = 0; - switch (type) { - case MTD: - read = mtd_read_data(ctx, p, next); - break; - - case EMMC: - read = ota_fread(p, 1, next, dev); - break; - } + size_t read = ota_fread(p, 1, next, dev); if (next != read) { printf("short read (%zu bytes of %zu) for partition \"%s\"\n", read, next, partition); @@ -234,16 +187,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { } } - switch (type) { - case MTD: - mtd_read_close(ctx); - break; - - case EMMC: - ota_fclose(dev); - break; - } - + ota_fclose(dev); if (!found) { // Ran off the end of the list of (size,sha1) pairs without finding a match. @@ -302,7 +246,7 @@ int SaveFileContents(const char* filename, const FileContents* file) { } // Write a memory buffer to 'target' partition, a string of the form -// "MTD:[:...]" or "EMMC:[:...]". The target name +// "EMMC:[:...]". The target name // might contain multiple colons, but WriteToPartition() only uses the first // two and ignores the rest. Return 0 on success. int WriteToPartition(const unsigned char* data, size_t len, const char* target) { @@ -314,165 +258,117 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) return -1; } - enum PartitionType type; - if (pieces[0] == "MTD") { - type = MTD; - } else if (pieces[0] == "EMMC") { - type = EMMC; - } else { + if (pieces[0] != "EMMC") { printf("WriteToPartition called with bad target (%s)\n", target); return -1; } const char* partition = pieces[1].c_str(); - switch (type) { - case MTD: { - if (!mtd_partitions_scanned) { - mtd_scan_partitions(); - mtd_partitions_scanned = true; - } - - const MtdPartition* mtd = mtd_find_partition_by_name(partition); - if (mtd == NULL) { - printf("mtd partition \"%s\" not found for writing\n", partition); - return -1; - } - - MtdWriteContext* ctx = mtd_write_partition(mtd); - if (ctx == NULL) { - printf("failed to init mtd partition \"%s\" for writing\n", partition); - return -1; - } + size_t start = 0; + bool success = false; + int fd = ota_open(partition, O_RDWR | O_SYNC); + if (fd < 0) { + printf("failed to open %s: %s\n", partition, strerror(errno)); + return -1; + } - size_t written = mtd_write_data(ctx, reinterpret_cast(data), len); - if (written != len) { - printf("only wrote %zu of %zu bytes to MTD %s\n", written, len, partition); - mtd_write_close(ctx); - return -1; - } + for (size_t attempt = 0; attempt < 2; ++attempt) { + if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) { + printf("failed seek on %s: %s\n", partition, strerror(errno)); + return -1; + } + while (start < len) { + size_t to_write = len - start; + if (to_write > 1<<20) to_write = 1<<20; - if (mtd_erase_blocks(ctx, -1) < 0) { - printf("error finishing mtd write of %s\n", partition); - mtd_write_close(ctx); + ssize_t written = TEMP_FAILURE_RETRY(ota_write(fd, data+start, to_write)); + if (written == -1) { + printf("failed write writing to %s: %s\n", partition, strerror(errno)); return -1; } + start += written; + } + if (ota_fsync(fd) != 0) { + printf("failed to sync to %s (%s)\n", partition, strerror(errno)); + return -1; + } + if (ota_close(fd) != 0) { + printf("failed to close %s (%s)\n", partition, strerror(errno)); + return -1; + } + fd = ota_open(partition, O_RDONLY); + if (fd < 0) { + printf("failed to reopen %s for verify (%s)\n", partition, strerror(errno)); + return -1; + } - if (mtd_write_close(ctx)) { - printf("error closing mtd write of %s\n", partition); - return -1; - } - break; + // Drop caches so our subsequent verification read + // won't just be reading the cache. + sync(); + int dc = ota_open("/proc/sys/vm/drop_caches", O_WRONLY); + if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) { + printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno)); + } else { + printf(" caches dropped\n"); } + ota_close(dc); + sleep(1); - case EMMC: { - size_t start = 0; - bool success = false; - int fd = ota_open(partition, O_RDWR | O_SYNC); - if (fd < 0) { - printf("failed to open %s: %s\n", partition, strerror(errno)); - return -1; + // verify + if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) { + printf("failed to seek back to beginning of %s: %s\n", + partition, strerror(errno)); + return -1; + } + unsigned char buffer[4096]; + start = len; + for (size_t p = 0; p < len; p += sizeof(buffer)) { + size_t to_read = len - p; + if (to_read > sizeof(buffer)) { + to_read = sizeof(buffer); } - for (size_t attempt = 0; attempt < 2; ++attempt) { - if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) { - printf("failed seek on %s: %s\n", partition, strerror(errno)); + size_t so_far = 0; + while (so_far < to_read) { + ssize_t read_count = + TEMP_FAILURE_RETRY(ota_read(fd, buffer+so_far, to_read-so_far)); + if (read_count == -1) { + printf("verify read error %s at %zu: %s\n", + partition, p, strerror(errno)); return -1; } - while (start < len) { - size_t to_write = len - start; - if (to_write > 1<<20) to_write = 1<<20; - - ssize_t written = TEMP_FAILURE_RETRY(ota_write(fd, data+start, to_write)); - if (written == -1) { - printf("failed write writing to %s: %s\n", partition, strerror(errno)); - return -1; - } - start += written; - } - if (ota_fsync(fd) != 0) { - printf("failed to sync to %s (%s)\n", partition, strerror(errno)); - return -1; - } - if (ota_close(fd) != 0) { - printf("failed to close %s (%s)\n", partition, strerror(errno)); - return -1; - } - fd = ota_open(partition, O_RDONLY); - if (fd < 0) { - printf("failed to reopen %s for verify (%s)\n", partition, strerror(errno)); - return -1; - } - - // Drop caches so our subsequent verification read - // won't just be reading the cache. - sync(); - int dc = ota_open("/proc/sys/vm/drop_caches", O_WRONLY); - if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) { - printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno)); - } else { - printf(" caches dropped\n"); - } - ota_close(dc); - sleep(1); - - // verify - if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) { - printf("failed to seek back to beginning of %s: %s\n", - partition, strerror(errno)); - return -1; - } - unsigned char buffer[4096]; - start = len; - for (size_t p = 0; p < len; p += sizeof(buffer)) { - size_t to_read = len - p; - if (to_read > sizeof(buffer)) { - to_read = sizeof(buffer); - } - - size_t so_far = 0; - while (so_far < to_read) { - ssize_t read_count = - TEMP_FAILURE_RETRY(ota_read(fd, buffer+so_far, to_read-so_far)); - if (read_count == -1) { - printf("verify read error %s at %zu: %s\n", - partition, p, strerror(errno)); - return -1; - } - if (static_cast(read_count) < to_read) { - printf("short verify read %s at %zu: %zd %zu %s\n", - partition, p, read_count, to_read, strerror(errno)); - } - so_far += read_count; - } - - if (memcmp(buffer, data+p, to_read) != 0) { - printf("verification failed starting at %zu\n", p); - start = p; - break; - } - } - - if (start == len) { - printf("verification read succeeded (attempt %zu)\n", attempt+1); - success = true; - break; + if (static_cast(read_count) < to_read) { + printf("short verify read %s at %zu: %zd %zu %s\n", + partition, p, read_count, to_read, strerror(errno)); } + so_far += read_count; } - if (!success) { - printf("failed to verify after all attempts\n"); - return -1; + if (memcmp(buffer, data+p, to_read) != 0) { + printf("verification failed starting at %zu\n", p); + start = p; + break; } + } - if (ota_close(fd) != 0) { - printf("error closing %s (%s)\n", partition, strerror(errno)); - return -1; - } - sync(); + if (start == len) { + printf("verification read succeeded (attempt %zu)\n", attempt+1); + success = true; break; } } + if (!success) { + printf("failed to verify after all attempts\n"); + return -1; + } + + if (ota_close(fd) != 0) { + printf("error closing %s (%s)\n", partition, strerror(errno)); + return -1; + } + sync(); + return 0; } @@ -729,7 +625,7 @@ int applypatch_flash(const char* source_filename, const char* target_filename, std::string target_str(target_filename); std::vector pieces = android::base::Split(target_str, ":"); - if (pieces.size() != 2 || (pieces[0] != "MTD" && pieces[0] != "EMMC")) { + if (pieces.size() != 2 || pieces[0] != "EMMC") { printf("invalid target name \"%s\"", target_filename); return 1; } @@ -778,8 +674,7 @@ static int GenerateTarget(FileContents* source_file, FileContents* source_to_use; int made_copy = 0; - bool target_is_partition = (strncmp(target_filename, "MTD:", 4) == 0 || - strncmp(target_filename, "EMMC:", 5) == 0); + bool target_is_partition = (strncmp(target_filename, "EMMC:", 5) == 0); const std::string tmp_target_filename = std::string(target_filename) + ".patch"; // assume that target_filename (eg "/system/app/Foo.apk") is located @@ -860,8 +755,7 @@ static int GenerateTarget(FileContents* source_file, // copy the source file to cache, then delete it from the original // location. - if (strncmp(source_filename, "MTD:", 4) == 0 || - strncmp(source_filename, "EMMC:", 5) == 0) { + if (strncmp(source_filename, "EMMC:", 5) == 0) { // It's impossible to free space on the target filesystem by // deleting the source if the source is a partition. If // we're ever in a state where we need to do this, fail. -- cgit v1.2.3 From 71e182bc3879a53f04a50de9d25c333163cb7c76 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Wed, 31 Aug 2016 18:06:33 -0700 Subject: Check an edge case when read(2) returns 0 We might end up in an infinite loop if read(2) reached EOF unexpectedly. The problematic code in uncrypt mentioned in the bug has been fixed by switching to libbase ReadFully(). So I grepped through the recovery code and fixed some other occurences of the issue. Bug: 31073201 Change-Id: Ib867029158ba23363b8f85d61c25058a635c5a6b --- applypatch/applypatch.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'applypatch/applypatch.cpp') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 02a3c6e41..e52ef99dc 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -336,6 +336,9 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) printf("verify read error %s at %zu: %s\n", partition, p, strerror(errno)); return -1; + } else if (read_count == 0) { + printf("verify read reached unexpected EOF, %s at %zu\n", partition, p); + return -1; } if (static_cast(read_count) < to_read) { printf("short verify read %s at %zu: %zd %zu %s\n", -- cgit v1.2.3 From aced5d9e4e438ba478ce54f9217166b8ab7cc24f Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Wed, 12 Oct 2016 10:55:04 -0700 Subject: Change StringValue to use std::string Changing the field of 'Value' in edify to std::string from char*. Meanwhile cleaning up the users of 'Value' and switching them to cpp style. Test: compontent tests passed. Bug: 31713288 Change-Id: Iec5a7d601b1e4ca40935bf1c70d325dafecec235 --- applypatch/applypatch.cpp | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) (limited to 'applypatch/applypatch.cpp') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index e52ef99dc..cf155607b 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -408,11 +408,10 @@ int ParseSha1(const char* str, uint8_t* digest) { // Search an array of sha1 strings for one matching the given sha1. // Return the index of the match on success, or -1 if no match is // found. -int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str, - int num_patches) { - uint8_t patch_sha1[SHA_DIGEST_LENGTH]; - for (int i = 0; i < num_patches; ++i) { - if (ParseSha1(patch_sha1_str[i], patch_sha1) == 0 && +int FindMatchingPatch(uint8_t* sha1, const std::vector& patch_sha1_str) { + for (size_t i = 0; i < patch_sha1_str.size(); ++i) { + uint8_t patch_sha1[SHA_DIGEST_LENGTH]; + if (ParseSha1(patch_sha1_str[i].c_str(), patch_sha1) == 0 && memcmp(patch_sha1, sha1, SHA_DIGEST_LENGTH) == 0) { return i; } @@ -423,8 +422,7 @@ int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str, // Returns 0 if the contents of the file (argv[2]) or the cached file // match any of the sha1's on the command line (argv[3:]). Returns // nonzero otherwise. -int applypatch_check(const char* filename, int num_patches, - char** const patch_sha1_str) { +int applypatch_check(const char* filename, const std::vector& patch_sha1_str) { FileContents file; // It's okay to specify no sha1s; the check will pass if the @@ -432,8 +430,7 @@ int applypatch_check(const char* filename, int num_patches, // partitions, where the filename encodes the sha1s; no need to // check them twice.) if (LoadFileContents(filename, &file) != 0 || - (num_patches > 0 && - FindMatchingPatch(file.sha1, patch_sha1_str, num_patches) < 0)) { + FindMatchingPatch(file.sha1, patch_sha1_str) < 0) { printf("file \"%s\" doesn't have any of expected " "sha1 sums; checking cache\n", filename); @@ -448,7 +445,7 @@ int applypatch_check(const char* filename, int num_patches, return 1; } - if (FindMatchingPatch(file.sha1, patch_sha1_str, num_patches) < 0) { + if (FindMatchingPatch(file.sha1, patch_sha1_str) < 0) { printf("cache bits don't match any sha1 for \"%s\"\n", filename); return 1; } @@ -532,8 +529,7 @@ int applypatch(const char* source_filename, const char* target_filename, const char* target_sha1_str, size_t target_size, - int num_patches, - char** const patch_sha1_str, + const std::vector& patch_sha1_str, Value** patch_data, Value* bonus_data) { printf("patch %s: ", source_filename); @@ -573,7 +569,7 @@ int applypatch(const char* source_filename, } if (!source_file.data.empty()) { - int to_use = FindMatchingPatch(source_file.sha1, patch_sha1_str, num_patches); + int to_use = FindMatchingPatch(source_file.sha1, patch_sha1_str); if (to_use >= 0) { source_patch_value = patch_data[to_use]; } @@ -589,7 +585,7 @@ int applypatch(const char* source_filename, return 1; } - int to_use = FindMatchingPatch(copy_file.sha1, patch_sha1_str, num_patches); + int to_use = FindMatchingPatch(copy_file.sha1, patch_sha1_str); if (to_use >= 0) { copy_patch_value = patch_data[to_use]; } @@ -701,8 +697,8 @@ static int GenerateTarget(FileContents* source_file, printf("patch is not a blob\n"); return 1; } - char* header = patch->data; - ssize_t header_bytes_read = patch->size; + const char* header = &patch->data[0]; + size_t header_bytes_read = patch->data.size(); bool use_bsdiff = false; if (header_bytes_read >= 8 && memcmp(header, "BSDIFF40", 8) == 0) { use_bsdiff = true; -- cgit v1.2.3 From 984d7d058e65ddc1b8a1ffc79a5f178ad88dd596 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Tue, 18 Oct 2016 13:37:18 -0700 Subject: Fix applypatch_check failure when applying update on angler Applypatch_check should be skipped if no sha is specified. As the comments said: "It's okay to specify no sha1s; the check will pass if the LoadFileContents is successful. Useful for reading partitions, where the filename encodes the sha1s." Test: The update package applied on angler successfully. Bug: 32243751 Change-Id: Ib8f3dadf19f745c2dbd350d60da46ab12d75bc87 --- applypatch/applypatch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'applypatch/applypatch.cpp') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index cf155607b..48e4c8386 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -430,7 +430,7 @@ int applypatch_check(const char* filename, const std::vector& patch // partitions, where the filename encodes the sha1s; no need to // check them twice.) if (LoadFileContents(filename, &file) != 0 || - FindMatchingPatch(file.sha1, patch_sha1_str) < 0) { + (patch_sha1_str.size() > 0 && FindMatchingPatch(file.sha1, patch_sha1_str) < 0)) { printf("file \"%s\" doesn't have any of expected " "sha1 sums; checking cache\n", filename); -- cgit v1.2.3 From fada91ccf2b31d69d72899388b1833186d763d1a Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 27 Oct 2016 18:16:06 -0700 Subject: applypatch: Switch the parameter of Value** to std::vector. Test: Unit tests and install-recovery.sh pass on angler and dragon. Change-Id: I328e6554edca667cf850f5584ebf1ac211e3d4d1 --- applypatch/applypatch.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'applypatch/applypatch.cpp') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 48e4c8386..9d505f9f6 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -530,8 +530,8 @@ int applypatch(const char* source_filename, const char* target_sha1_str, size_t target_size, const std::vector& patch_sha1_str, - Value** patch_data, - Value* bonus_data) { + const std::vector>& patch_data, + const Value* bonus_data) { printf("patch %s: ", source_filename); if (target_filename[0] == '-' && target_filename[1] == '\0') { @@ -546,8 +546,8 @@ int applypatch(const char* source_filename, FileContents copy_file; FileContents source_file; - const Value* source_patch_value = NULL; - const Value* copy_patch_value = NULL; + const Value* source_patch_value = nullptr; + const Value* copy_patch_value = nullptr; // We try to load the target file into the source_file object. if (LoadFileContents(target_filename, &source_file) == 0) { @@ -571,11 +571,11 @@ int applypatch(const char* source_filename, if (!source_file.data.empty()) { int to_use = FindMatchingPatch(source_file.sha1, patch_sha1_str); if (to_use >= 0) { - source_patch_value = patch_data[to_use]; + source_patch_value = patch_data[to_use].get(); } } - if (source_patch_value == NULL) { + if (source_patch_value == nullptr) { source_file.data.clear(); printf("source file is bad; trying copy\n"); @@ -587,10 +587,10 @@ int applypatch(const char* source_filename, int to_use = FindMatchingPatch(copy_file.sha1, patch_sha1_str); if (to_use >= 0) { - copy_patch_value = patch_data[to_use]; + copy_patch_value = patch_data[to_use].get(); } - if (copy_patch_value == NULL) { + if (copy_patch_value == nullptr) { // fail. printf("copy file doesn't match source SHA-1s either\n"); return 1; -- cgit v1.2.3 From 8fce75a0697d07deed7dc81b0b9384920d8a46a4 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 10 Nov 2016 12:33:41 -0800 Subject: applypatch: Clean up LoadPartitionContents(). We don't need three vectors to sort the (size, SHA-1) pairs. Test: recovery_component_test passes. Test: Apply a package that calls apply_patch_check() to patch EMMC partitions. Change-Id: I4a6620630a6711f490822cf30f1e7fe5cea6ce49 --- applypatch/applypatch.cpp | 540 ++++++++++++++++++++++------------------------ 1 file changed, 257 insertions(+), 283 deletions(-) (limited to 'applypatch/applypatch.cpp') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 9d505f9f6..5483a68da 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "applypatch/applypatch.h" + #include #include #include @@ -27,16 +29,18 @@ #include #include +#include +#include +#include #include +#include -#include "openssl/sha.h" -#include "applypatch/applypatch.h" #include "edify/expr.h" #include "ota_io.h" #include "print_sha1.h" -static int LoadPartitionContents(const char* filename, FileContents* file); +static int LoadPartitionContents(const std::string& filename, FileContents* file); static ssize_t FileSink(const unsigned char* data, ssize_t len, void* token); static int GenerateTarget(FileContents* source_file, const Value* source_patch_value, @@ -48,39 +52,34 @@ static int GenerateTarget(FileContents* source_file, size_t target_size, const Value* bonus_data); -// Read a file into memory; store the file contents and associated -// metadata in *file. -// +// Read a file into memory; store the file contents and associated metadata in *file. // Return 0 on success. int LoadFileContents(const char* filename, FileContents* file) { - // A special 'filename' beginning with "EMMC:" means to - // load the contents of a partition. - if (strncmp(filename, "EMMC:", 5) == 0) { - return LoadPartitionContents(filename, file); - } + // A special 'filename' beginning with "EMMC:" means to load the contents of a partition. + if (strncmp(filename, "EMMC:", 5) == 0) { + return LoadPartitionContents(filename, file); + } - if (stat(filename, &file->st) != 0) { - printf("failed to stat \"%s\": %s\n", filename, strerror(errno)); - return -1; - } + if (stat(filename, &file->st) == -1) { + printf("failed to stat \"%s\": %s\n", filename, strerror(errno)); + return -1; + } - std::vector data(file->st.st_size); - FILE* f = ota_fopen(filename, "rb"); - if (f == NULL) { - printf("failed to open \"%s\": %s\n", filename, strerror(errno)); - return -1; - } + std::vector data(file->st.st_size); + std::unique_ptr f(ota_fopen(filename, "rb"), ota_fclose); + if (!f) { + printf("failed to open \"%s\": %s\n", filename, strerror(errno)); + return -1; + } - size_t bytes_read = ota_fread(data.data(), 1, data.size(), f); - if (bytes_read != data.size()) { - printf("short read of \"%s\" (%zu bytes of %zu)\n", filename, bytes_read, data.size()); - ota_fclose(f); - return -1; - } - ota_fclose(f); - file->data = std::move(data); - SHA1(file->data.data(), file->data.size(), file->sha1); - return 0; + size_t bytes_read = ota_fread(data.data(), 1, data.size(), f.get()); + if (bytes_read != data.size()) { + printf("short read of \"%s\" (%zu bytes of %zu)\n", filename, bytes_read, data.size()); + return -1; + } + file->data = std::move(data); + SHA1(file->data.data(), file->data.size(), file->sha1); + return 0; } // Load the contents of an EMMC partition into the provided @@ -97,114 +96,98 @@ int LoadFileContents(const char* filename, FileContents* file) { // "end-of-file" marker), so the caller must specify the possible // lengths and the hash of the data, and we'll do the load expecting // to find one of those hashes. -static int LoadPartitionContents(const char* filename, FileContents* file) { - std::string copy(filename); - std::vector pieces = android::base::Split(copy, ":"); - if (pieces.size() < 4 || pieces.size() % 2 != 0) { - printf("LoadPartitionContents called with bad filename (%s)\n", filename); - return -1; - } - - if (pieces[0] != "EMMC") { - printf("LoadPartitionContents called with bad filename (%s)\n", filename); +static int LoadPartitionContents(const std::string& filename, FileContents* file) { + std::vector pieces = android::base::Split(filename, ":"); + if (pieces.size() < 4 || pieces.size() % 2 != 0 || pieces[0] != "EMMC") { + printf("LoadPartitionContents called with bad filename \"%s\"\n", filename.c_str()); + return -1; + } + + size_t pair_count = (pieces.size() - 2) / 2; // # of (size, sha1) pairs in filename + std::vector> pairs; + for (size_t i = 0; i < pair_count; ++i) { + size_t size; + if (!android::base::ParseUint(pieces[i * 2 + 2], &size) || size == 0) { + printf("LoadPartitionContents called with bad size \"%s\"\n", pieces[i * 2 + 2].c_str()); + return -1; + } + pairs.push_back({ size, pieces[i * 2 + 3] }); + } + + // Sort the pairs array so that they are in order of increasing size. + std::sort(pairs.begin(), pairs.end()); + + const char* partition = pieces[1].c_str(); + std::unique_ptr dev(ota_fopen(partition, "rb"), ota_fclose); + if (!dev) { + printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno)); + return -1; + } + + SHA_CTX sha_ctx; + SHA1_Init(&sha_ctx); + + // Allocate enough memory to hold the largest size. + std::vector buffer(pairs[pair_count - 1].first); + unsigned char* buffer_ptr = buffer.data(); + size_t buffer_size = 0; // # bytes read so far + bool found = false; + + for (const auto& pair : pairs) { + size_t current_size = pair.first; + const std::string& current_sha1 = pair.second; + + // Read enough additional bytes to get us up to the next size. (Again, + // we're trying the possibilities in order of increasing size). + size_t next = current_size - buffer_size; + if (next > 0) { + size_t read = ota_fread(buffer_ptr, 1, next, dev.get()); + if (next != read) { + printf("short read (%zu bytes of %zu) for partition \"%s\"\n", read, next, partition); return -1; - } - const char* partition = pieces[1].c_str(); - - size_t pairs = (pieces.size() - 2) / 2; // # of (size, sha1) pairs in filename - std::vector index(pairs); - std::vector size(pairs); - std::vector sha1sum(pairs); - - for (size_t i = 0; i < pairs; ++i) { - size[i] = strtol(pieces[i*2+2].c_str(), NULL, 10); - if (size[i] == 0) { - printf("LoadPartitionContents called with bad size (%s)\n", filename); - return -1; - } - sha1sum[i] = pieces[i*2+3].c_str(); - index[i] = i; + } + SHA1_Update(&sha_ctx, buffer_ptr, read); + buffer_size += read; + buffer_ptr += read; } - // Sort the index[] array so it indexes the pairs in order of increasing size. - sort(index.begin(), index.end(), - [&](const size_t& i, const size_t& j) { - return (size[i] < size[j]); - } - ); + // Duplicate the SHA context and finalize the duplicate so we can + // check it against this pair's expected hash. + SHA_CTX temp_ctx; + memcpy(&temp_ctx, &sha_ctx, sizeof(SHA_CTX)); + uint8_t sha_so_far[SHA_DIGEST_LENGTH]; + SHA1_Final(sha_so_far, &temp_ctx); - FILE* dev = ota_fopen(partition, "rb"); - if (dev == NULL) { - printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno)); - return -1; - } - - SHA_CTX sha_ctx; - SHA1_Init(&sha_ctx); uint8_t parsed_sha[SHA_DIGEST_LENGTH]; - - // Allocate enough memory to hold the largest size. - std::vector data(size[index[pairs-1]]); - char* p = reinterpret_cast(data.data()); - size_t data_size = 0; // # bytes read so far - bool found = false; - - for (size_t i = 0; i < pairs; ++i) { - // Read enough additional bytes to get us up to the next size. (Again, - // we're trying the possibilities in order of increasing size). - size_t next = size[index[i]] - data_size; - if (next > 0) { - size_t read = ota_fread(p, 1, next, dev); - if (next != read) { - printf("short read (%zu bytes of %zu) for partition \"%s\"\n", - read, next, partition); - return -1; - } - SHA1_Update(&sha_ctx, p, read); - data_size += read; - p += read; - } - - // Duplicate the SHA context and finalize the duplicate so we can - // check it against this pair's expected hash. - SHA_CTX temp_ctx; - memcpy(&temp_ctx, &sha_ctx, sizeof(SHA_CTX)); - uint8_t sha_so_far[SHA_DIGEST_LENGTH]; - SHA1_Final(sha_so_far, &temp_ctx); - - if (ParseSha1(sha1sum[index[i]].c_str(), parsed_sha) != 0) { - printf("failed to parse sha1 %s in %s\n", sha1sum[index[i]].c_str(), filename); - return -1; - } - - if (memcmp(sha_so_far, parsed_sha, SHA_DIGEST_LENGTH) == 0) { - // we have a match. stop reading the partition; we'll return - // the data we've read so far. - printf("partition read matched size %zu sha %s\n", - size[index[i]], sha1sum[index[i]].c_str()); - found = true; - break; - } + if (ParseSha1(current_sha1.c_str(), parsed_sha) != 0) { + printf("failed to parse SHA-1 %s in %s\n", current_sha1.c_str(), filename.c_str()); + return -1; } - ota_fclose(dev); - - if (!found) { - // Ran off the end of the list of (size,sha1) pairs without finding a match. - printf("contents of partition \"%s\" didn't match %s\n", partition, filename); - return -1; + if (memcmp(sha_so_far, parsed_sha, SHA_DIGEST_LENGTH) == 0) { + // We have a match. Stop reading the partition; we'll return the data we've read so far. + printf("partition read matched size %zu SHA-1 %s\n", current_size, current_sha1.c_str()); + found = true; + break; } + } - SHA1_Final(file->sha1, &sha_ctx); + if (!found) { + // Ran off the end of the list of (size, sha1) pairs without finding a match. + printf("contents of partition \"%s\" didn't match %s\n", partition, filename.c_str()); + return -1; + } - data.resize(data_size); - file->data = std::move(data); - // Fake some stat() info. - file->st.st_mode = 0644; - file->st.st_uid = 0; - file->st.st_gid = 0; + SHA1_Final(file->sha1, &sha_ctx); - return 0; + buffer.resize(buffer_size); + file->data = std::move(buffer); + // Fake some stat() info. + file->st.st_mode = 0644; + file->st.st_uid = 0; + file->st.st_gid = 0; + + return 0; } @@ -250,131 +233,124 @@ int SaveFileContents(const char* filename, const FileContents* file) { // might contain multiple colons, but WriteToPartition() only uses the first // two and ignores the rest. Return 0 on success. int WriteToPartition(const unsigned char* data, size_t len, const char* target) { - std::string copy(target); - std::vector pieces = android::base::Split(copy, ":"); - - if (pieces.size() < 2) { - printf("WriteToPartition called with bad target (%s)\n", target); - return -1; - } - - if (pieces[0] != "EMMC") { - printf("WriteToPartition called with bad target (%s)\n", target); - return -1; - } - const char* partition = pieces[1].c_str(); - - size_t start = 0; - bool success = false; - int fd = ota_open(partition, O_RDWR | O_SYNC); - if (fd < 0) { - printf("failed to open %s: %s\n", partition, strerror(errno)); - return -1; - } - - for (size_t attempt = 0; attempt < 2; ++attempt) { - if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) { - printf("failed seek on %s: %s\n", partition, strerror(errno)); - return -1; - } - while (start < len) { - size_t to_write = len - start; - if (to_write > 1<<20) to_write = 1<<20; - - ssize_t written = TEMP_FAILURE_RETRY(ota_write(fd, data+start, to_write)); - if (written == -1) { - printf("failed write writing to %s: %s\n", partition, strerror(errno)); - return -1; - } - start += written; - } - if (ota_fsync(fd) != 0) { - printf("failed to sync to %s (%s)\n", partition, strerror(errno)); - return -1; - } - if (ota_close(fd) != 0) { - printf("failed to close %s (%s)\n", partition, strerror(errno)); - return -1; - } - fd = ota_open(partition, O_RDONLY); - if (fd < 0) { - printf("failed to reopen %s for verify (%s)\n", partition, strerror(errno)); - return -1; - } + std::vector pieces = android::base::Split(std::string(target), ":"); - // Drop caches so our subsequent verification read - // won't just be reading the cache. - sync(); - int dc = ota_open("/proc/sys/vm/drop_caches", O_WRONLY); - if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) { - printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno)); - } else { - printf(" caches dropped\n"); - } - ota_close(dc); - sleep(1); - - // verify - if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) { - printf("failed to seek back to beginning of %s: %s\n", - partition, strerror(errno)); - return -1; - } - unsigned char buffer[4096]; - start = len; - for (size_t p = 0; p < len; p += sizeof(buffer)) { - size_t to_read = len - p; - if (to_read > sizeof(buffer)) { - to_read = sizeof(buffer); - } + if (pieces.size() < 2 || pieces[0] != "EMMC") { + printf("WriteToPartition called with bad target (%s)\n", target); + return -1; + } - size_t so_far = 0; - while (so_far < to_read) { - ssize_t read_count = - TEMP_FAILURE_RETRY(ota_read(fd, buffer+so_far, to_read-so_far)); - if (read_count == -1) { - printf("verify read error %s at %zu: %s\n", - partition, p, strerror(errno)); - return -1; - } else if (read_count == 0) { - printf("verify read reached unexpected EOF, %s at %zu\n", partition, p); - return -1; - } - if (static_cast(read_count) < to_read) { - printf("short verify read %s at %zu: %zd %zu %s\n", - partition, p, read_count, to_read, strerror(errno)); - } - so_far += read_count; - } + const char* partition = pieces[1].c_str(); - if (memcmp(buffer, data+p, to_read) != 0) { - printf("verification failed starting at %zu\n", p); - start = p; - break; - } - } + size_t start = 0; + bool success = false; + int fd = ota_open(partition, O_RDWR | O_SYNC); + if (fd < 0) { + printf("failed to open %s: %s\n", partition, strerror(errno)); + return -1; + } - if (start == len) { - printf("verification read succeeded (attempt %zu)\n", attempt+1); - success = true; - break; - } + for (size_t attempt = 0; attempt < 2; ++attempt) { + if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) { + printf("failed seek on %s: %s\n", partition, strerror(errno)); + return -1; } + while (start < len) { + size_t to_write = len - start; + if (to_write > 1 << 20) to_write = 1 << 20; - if (!success) { - printf("failed to verify after all attempts\n"); + ssize_t written = TEMP_FAILURE_RETRY(ota_write(fd, data + start, to_write)); + if (written == -1) { + printf("failed write writing to %s: %s\n", partition, strerror(errno)); return -1; + } + start += written; } + if (ota_fsync(fd) != 0) { + printf("failed to sync to %s (%s)\n", partition, strerror(errno)); + return -1; + } if (ota_close(fd) != 0) { - printf("error closing %s (%s)\n", partition, strerror(errno)); - return -1; + printf("failed to close %s (%s)\n", partition, strerror(errno)); + return -1; } + + fd = ota_open(partition, O_RDONLY); + if (fd < 0) { + printf("failed to reopen %s for verify (%s)\n", partition, strerror(errno)); + return -1; + } + + // Drop caches so our subsequent verification read won't just be reading the cache. sync(); + int dc = ota_open("/proc/sys/vm/drop_caches", O_WRONLY); + if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) { + printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno)); + } else { + printf(" caches dropped\n"); + } + ota_close(dc); + sleep(1); + + // verify + if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) { + printf("failed to seek back to beginning of %s: %s\n", partition, strerror(errno)); + return -1; + } + + unsigned char buffer[4096]; + start = len; + for (size_t p = 0; p < len; p += sizeof(buffer)) { + size_t to_read = len - p; + if (to_read > sizeof(buffer)) { + to_read = sizeof(buffer); + } + + size_t so_far = 0; + while (so_far < to_read) { + ssize_t read_count = TEMP_FAILURE_RETRY(ota_read(fd, buffer + so_far, to_read - so_far)); + if (read_count == -1) { + printf("verify read error %s at %zu: %s\n", partition, p, strerror(errno)); + return -1; + } else if (read_count == 0) { + printf("verify read reached unexpected EOF, %s at %zu\n", partition, p); + return -1; + } + if (static_cast(read_count) < to_read) { + printf("short verify read %s at %zu: %zd %zu %s\n", partition, p, read_count, to_read, + strerror(errno)); + } + so_far += read_count; + } + + if (memcmp(buffer, data + p, to_read) != 0) { + printf("verification failed starting at %zu\n", p); + start = p; + break; + } + } + + if (start == len) { + printf("verification read succeeded (attempt %zu)\n", attempt + 1); + success = true; + break; + } + } + + if (!success) { + printf("failed to verify after all attempts\n"); + return -1; + } - return 0; -} + if (ota_close(fd) != 0) { + printf("error closing %s (%s)\n", partition, strerror(errno)); + return -1; + } + sync(); + return 0; +} // Take a string 'str' of 40 hex digits and parse it into the 20 // byte array 'digest'. 'str' may contain only the digest or be of @@ -409,48 +385,46 @@ int ParseSha1(const char* str, uint8_t* digest) { // Return the index of the match on success, or -1 if no match is // found. int FindMatchingPatch(uint8_t* sha1, const std::vector& patch_sha1_str) { - for (size_t i = 0; i < patch_sha1_str.size(); ++i) { - uint8_t patch_sha1[SHA_DIGEST_LENGTH]; - if (ParseSha1(patch_sha1_str[i].c_str(), patch_sha1) == 0 && - memcmp(patch_sha1, sha1, SHA_DIGEST_LENGTH) == 0) { - return i; - } - } - return -1; + for (size_t i = 0; i < patch_sha1_str.size(); ++i) { + uint8_t patch_sha1[SHA_DIGEST_LENGTH]; + if (ParseSha1(patch_sha1_str[i].c_str(), patch_sha1) == 0 && + memcmp(patch_sha1, sha1, SHA_DIGEST_LENGTH) == 0) { + return i; + } + } + return -1; } // Returns 0 if the contents of the file (argv[2]) or the cached file // match any of the sha1's on the command line (argv[3:]). Returns // nonzero otherwise. int applypatch_check(const char* filename, const std::vector& patch_sha1_str) { - FileContents file; - - // It's okay to specify no sha1s; the check will pass if the - // LoadFileContents is successful. (Useful for reading - // partitions, where the filename encodes the sha1s; no need to - // check them twice.) - if (LoadFileContents(filename, &file) != 0 || - (patch_sha1_str.size() > 0 && FindMatchingPatch(file.sha1, patch_sha1_str) < 0)) { - printf("file \"%s\" doesn't have any of expected " - "sha1 sums; checking cache\n", filename); - - // If the source file is missing or corrupted, it might be because - // we were killed in the middle of patching it. A copy of it - // should have been made in CACHE_TEMP_SOURCE. If that file - // exists and matches the sha1 we're looking for, the check still - // passes. - - if (LoadFileContents(CACHE_TEMP_SOURCE, &file) != 0) { - printf("failed to load cache file\n"); - return 1; - } - - if (FindMatchingPatch(file.sha1, patch_sha1_str) < 0) { - printf("cache bits don't match any sha1 for \"%s\"\n", filename); - return 1; - } - } - return 0; + FileContents file; + + // It's okay to specify no sha1s; the check will pass if the + // LoadFileContents is successful. (Useful for reading + // partitions, where the filename encodes the sha1s; no need to + // check them twice.) + if (LoadFileContents(filename, &file) != 0 || + (!patch_sha1_str.empty() && FindMatchingPatch(file.sha1, patch_sha1_str) < 0)) { + printf("file \"%s\" doesn't have any of expected sha1 sums; checking cache\n", filename); + + // If the source file is missing or corrupted, it might be because + // we were killed in the middle of patching it. A copy of it + // should have been made in CACHE_TEMP_SOURCE. If that file + // exists and matches the sha1 we're looking for, the check still + // passes. + if (LoadFileContents(CACHE_TEMP_SOURCE, &file) != 0) { + printf("failed to load cache file\n"); + return 1; + } + + if (FindMatchingPatch(file.sha1, patch_sha1_str) < 0) { + printf("cache bits don't match any sha1 for \"%s\"\n", filename); + return 1; + } + } + return 0; } int ShowLicenses() { @@ -544,10 +518,8 @@ int applypatch(const char* source_filename, return 1; } - FileContents copy_file; FileContents source_file; const Value* source_patch_value = nullptr; - const Value* copy_patch_value = nullptr; // We try to load the target file into the source_file object. if (LoadFileContents(target_filename, &source_file) == 0) { @@ -575,6 +547,8 @@ int applypatch(const char* source_filename, } } + FileContents copy_file; + const Value* copy_patch_value = nullptr; if (source_patch_value == nullptr) { source_file.data.clear(); printf("source file is bad; trying copy\n"); @@ -620,7 +594,6 @@ int applypatch_flash(const char* source_filename, const char* target_filename, return 1; } - FileContents source_file; std::string target_str(target_filename); std::vector pieces = android::base::Split(target_str, ":"); @@ -633,12 +606,13 @@ int applypatch_flash(const char* source_filename, const char* target_filename, pieces.push_back(std::to_string(target_size)); pieces.push_back(target_sha1_str); std::string fullname = android::base::Join(pieces, ':'); - if (LoadPartitionContents(fullname.c_str(), &source_file) == 0 && + FileContents source_file; + if (LoadPartitionContents(fullname, &source_file) == 0 && memcmp(source_file.sha1, target_sha1, SHA_DIGEST_LENGTH) == 0) { - // The early-exit case: the image was already applied, this partition - // has the desired hash, nothing for us to do. - printf("already %s\n", short_sha1(target_sha1).c_str()); - return 0; + // The early-exit case: the image was already applied, this partition + // has the desired hash, nothing for us to do. + printf("already %s\n", short_sha1(target_sha1).c_str()); + return 0; } if (LoadFileContents(source_filename, &source_file) == 0) { -- cgit v1.2.3 From 6e02ea92ec8af1da74f55e616b7cda82740dccc0 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 17 Nov 2016 11:24:07 -0800 Subject: applypatch: Use unique_fd to avoid leaking FDs. Add unique_fd that calls ota_close() instead of the default closer. Test: recovery_component_test passes. Test: Apply a package that calls apply_patch(). Change-Id: I0c19921731757934f76cf7d5215916673a8f2777 --- applypatch/applypatch.cpp | 552 +++++++++++++++++++++++----------------------- 1 file changed, 270 insertions(+), 282 deletions(-) (limited to 'applypatch/applypatch.cpp') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 5483a68da..9b84fa104 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -194,62 +194,59 @@ static int LoadPartitionContents(const std::string& filename, FileContents* file // Save the contents of the given FileContents object under the given // filename. Return 0 on success. int SaveFileContents(const char* filename, const FileContents* file) { - int fd = ota_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR); - if (fd < 0) { - printf("failed to open \"%s\" for write: %s\n", filename, strerror(errno)); - return -1; - } + unique_fd fd(ota_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR)); + if (fd == -1) { + printf("failed to open \"%s\" for write: %s\n", filename, strerror(errno)); + return -1; + } - ssize_t bytes_written = FileSink(file->data.data(), file->data.size(), &fd); - if (bytes_written != static_cast(file->data.size())) { - printf("short write of \"%s\" (%zd bytes of %zu) (%s)\n", - filename, bytes_written, file->data.size(), strerror(errno)); - ota_close(fd); - return -1; - } - if (ota_fsync(fd) != 0) { - printf("fsync of \"%s\" failed: %s\n", filename, strerror(errno)); - return -1; - } - if (ota_close(fd) != 0) { - printf("close of \"%s\" failed: %s\n", filename, strerror(errno)); - return -1; - } + ssize_t bytes_written = FileSink(file->data.data(), file->data.size(), &fd); + if (bytes_written != static_cast(file->data.size())) { + printf("short write of \"%s\" (%zd bytes of %zu): %s\n", filename, bytes_written, + file->data.size(), strerror(errno)); + return -1; + } + if (ota_fsync(fd) != 0) { + printf("fsync of \"%s\" failed: %s\n", filename, strerror(errno)); + return -1; + } + if (ota_close(fd) != 0) { + printf("close of \"%s\" failed: %s\n", filename, strerror(errno)); + return -1; + } - if (chmod(filename, file->st.st_mode) != 0) { - printf("chmod of \"%s\" failed: %s\n", filename, strerror(errno)); - return -1; - } - if (chown(filename, file->st.st_uid, file->st.st_gid) != 0) { - printf("chown of \"%s\" failed: %s\n", filename, strerror(errno)); - return -1; - } + if (chmod(filename, file->st.st_mode) != 0) { + printf("chmod of \"%s\" failed: %s\n", filename, strerror(errno)); + return -1; + } + if (chown(filename, file->st.st_uid, file->st.st_gid) != 0) { + printf("chown of \"%s\" failed: %s\n", filename, strerror(errno)); + return -1; + } - return 0; + return 0; } // Write a memory buffer to 'target' partition, a string of the form // "EMMC:[:...]". The target name // might contain multiple colons, but WriteToPartition() only uses the first // two and ignores the rest. Return 0 on success. -int WriteToPartition(const unsigned char* data, size_t len, const char* target) { - std::vector pieces = android::base::Split(std::string(target), ":"); - +int WriteToPartition(const unsigned char* data, size_t len, const std::string& target) { + std::vector pieces = android::base::Split(target, ":"); if (pieces.size() < 2 || pieces[0] != "EMMC") { - printf("WriteToPartition called with bad target (%s)\n", target); + printf("WriteToPartition called with bad target (%s)\n", target.c_str()); return -1; } const char* partition = pieces[1].c_str(); - - size_t start = 0; - bool success = false; - int fd = ota_open(partition, O_RDWR | O_SYNC); - if (fd < 0) { + unique_fd fd(ota_open(partition, O_RDWR)); + if (fd == -1) { printf("failed to open %s: %s\n", partition, strerror(errno)); return -1; } + size_t start = 0; + bool success = false; for (size_t attempt = 0; attempt < 2; ++attempt) { if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) { printf("failed seek on %s: %s\n", partition, strerror(errno)); @@ -268,23 +265,23 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) } if (ota_fsync(fd) != 0) { - printf("failed to sync to %s (%s)\n", partition, strerror(errno)); + printf("failed to sync to %s: %s\n", partition, strerror(errno)); return -1; } if (ota_close(fd) != 0) { - printf("failed to close %s (%s)\n", partition, strerror(errno)); + printf("failed to close %s: %s\n", partition, strerror(errno)); return -1; } - fd = ota_open(partition, O_RDONLY); - if (fd < 0) { - printf("failed to reopen %s for verify (%s)\n", partition, strerror(errno)); + fd.reset(ota_open(partition, O_RDONLY)); + if (fd == -1) { + printf("failed to reopen %s for verify: %s\n", partition, strerror(errno)); return -1; } // Drop caches so our subsequent verification read won't just be reading the cache. sync(); - int dc = ota_open("/proc/sys/vm/drop_caches", O_WRONLY); + unique_fd dc(ota_open("/proc/sys/vm/drop_caches", O_WRONLY)); if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) { printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno)); } else { @@ -293,7 +290,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) ota_close(dc); sleep(1); - // verify + // Verify. if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) { printf("failed to seek back to beginning of %s: %s\n", partition, strerror(errno)); return -1; @@ -318,8 +315,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) return -1; } if (static_cast(read_count) < to_read) { - printf("short verify read %s at %zu: %zd %zu %s\n", partition, p, read_count, to_read, - strerror(errno)); + printf("short verify read %s at %zu: %zd %zu\n", partition, p, read_count, to_read); } so_far += read_count; } @@ -343,8 +339,8 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) return -1; } - if (ota_close(fd) != 0) { - printf("error closing %s (%s)\n", partition, strerror(errno)); + if (ota_close(fd) == -1) { + printf("error closing %s: %s\n", partition, strerror(errno)); return -1; } sync(); @@ -586,50 +582,49 @@ int applypatch(const char* source_filename, */ int applypatch_flash(const char* source_filename, const char* target_filename, const char* target_sha1_str, size_t target_size) { - printf("flash %s: ", target_filename); + printf("flash %s: ", target_filename); - uint8_t target_sha1[SHA_DIGEST_LENGTH]; - if (ParseSha1(target_sha1_str, target_sha1) != 0) { - printf("failed to parse tgt-sha1 \"%s\"\n", target_sha1_str); - return 1; - } + uint8_t target_sha1[SHA_DIGEST_LENGTH]; + if (ParseSha1(target_sha1_str, target_sha1) != 0) { + printf("failed to parse tgt-sha1 \"%s\"\n", target_sha1_str); + return 1; + } - std::string target_str(target_filename); + std::string target_str(target_filename); + std::vector pieces = android::base::Split(target_str, ":"); + if (pieces.size() != 2 || pieces[0] != "EMMC") { + printf("invalid target name \"%s\"", target_filename); + return 1; + } - std::vector pieces = android::base::Split(target_str, ":"); - if (pieces.size() != 2 || pieces[0] != "EMMC") { - printf("invalid target name \"%s\"", target_filename); - return 1; - } + // Load the target into the source_file object to see if already applied. + pieces.push_back(std::to_string(target_size)); + pieces.push_back(target_sha1_str); + std::string fullname = android::base::Join(pieces, ':'); + FileContents source_file; + if (LoadPartitionContents(fullname, &source_file) == 0 && + memcmp(source_file.sha1, target_sha1, SHA_DIGEST_LENGTH) == 0) { + // The early-exit case: the image was already applied, this partition + // has the desired hash, nothing for us to do. + printf("already %s\n", short_sha1(target_sha1).c_str()); + return 0; + } - // Load the target into the source_file object to see if already applied. - pieces.push_back(std::to_string(target_size)); - pieces.push_back(target_sha1_str); - std::string fullname = android::base::Join(pieces, ':'); - FileContents source_file; - if (LoadPartitionContents(fullname, &source_file) == 0 && - memcmp(source_file.sha1, target_sha1, SHA_DIGEST_LENGTH) == 0) { - // The early-exit case: the image was already applied, this partition - // has the desired hash, nothing for us to do. - printf("already %s\n", short_sha1(target_sha1).c_str()); - return 0; - } - - if (LoadFileContents(source_filename, &source_file) == 0) { - if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_LENGTH) != 0) { - // The source doesn't have desired checksum. - printf("source \"%s\" doesn't have expected sha1 sum\n", source_filename); - printf("expected: %s, found: %s\n", short_sha1(target_sha1).c_str(), - short_sha1(source_file.sha1).c_str()); - return 1; - } + if (LoadFileContents(source_filename, &source_file) == 0) { + if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_LENGTH) != 0) { + // The source doesn't have desired checksum. + printf("source \"%s\" doesn't have expected sha1 sum\n", source_filename); + printf("expected: %s, found: %s\n", short_sha1(target_sha1).c_str(), + short_sha1(source_file.sha1).c_str()); + return 1; } + } - if (WriteToPartition(source_file.data.data(), target_size, target_filename) != 0) { - printf("write of copied data to %s failed\n", target_filename); - return 1; - } - return 0; + if (WriteToPartition(source_file.data.data(), target_size, target_filename) != 0) { + printf("write of copied data to %s failed\n", target_filename); + return 1; + } + return 0; } static int GenerateTarget(FileContents* source_file, @@ -641,221 +636,214 @@ static int GenerateTarget(FileContents* source_file, const uint8_t target_sha1[SHA_DIGEST_LENGTH], size_t target_size, const Value* bonus_data) { - int retry = 1; - SHA_CTX ctx; - std::string memory_sink_str; - FileContents* source_to_use; - int made_copy = 0; - - bool target_is_partition = (strncmp(target_filename, "EMMC:", 5) == 0); - const std::string tmp_target_filename = std::string(target_filename) + ".patch"; - - // assume that target_filename (eg "/system/app/Foo.apk") is located - // on the same filesystem as its top-level directory ("/system"). - // We need something that exists for calling statfs(). - std::string target_fs = target_filename; - auto slash_pos = target_fs.find('/', 1); - if (slash_pos != std::string::npos) { - target_fs.resize(slash_pos); - } - - const Value* patch; - if (source_patch_value != NULL) { - source_to_use = source_file; - patch = source_patch_value; - } else { - source_to_use = copy_file; - patch = copy_patch_value; - } - if (patch->type != VAL_BLOB) { - printf("patch is not a blob\n"); - return 1; - } - const char* header = &patch->data[0]; - size_t header_bytes_read = patch->data.size(); - bool use_bsdiff = false; - if (header_bytes_read >= 8 && memcmp(header, "BSDIFF40", 8) == 0) { - use_bsdiff = true; - } else if (header_bytes_read >= 8 && memcmp(header, "IMGDIFF2", 8) == 0) { - use_bsdiff = false; - } else { - printf("Unknown patch file format\n"); - return 1; - } + // assume that target_filename (eg "/system/app/Foo.apk") is located + // on the same filesystem as its top-level directory ("/system"). + // We need something that exists for calling statfs(). + std::string target_fs = target_filename; + auto slash_pos = target_fs.find('/', 1); + if (slash_pos != std::string::npos) { + target_fs.resize(slash_pos); + } - do { - // Is there enough room in the target filesystem to hold the patched - // file? - - if (target_is_partition) { - // If the target is a partition, we're actually going to - // write the output to /tmp and then copy it to the - // partition. statfs() always returns 0 blocks free for - // /tmp, so instead we'll just assume that /tmp has enough - // space to hold the file. - - // We still write the original source to cache, in case - // the partition write is interrupted. - if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) { - printf("not enough free space on /cache\n"); - return 1; - } - if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) { - printf("failed to back up source file\n"); - return 1; - } - made_copy = 1; - retry = 0; - } else { - int enough_space = 0; - if (retry > 0) { - size_t free_space = FreeSpaceForFile(target_fs.c_str()); - enough_space = - (free_space > (256 << 10)) && // 256k (two-block) minimum - (free_space > (target_size * 3 / 2)); // 50% margin of error - if (!enough_space) { - printf("target %zu bytes; free space %zu bytes; retry %d; enough %d\n", - target_size, free_space, retry, enough_space); - } - } - - if (!enough_space) { - retry = 0; - } - - if (!enough_space && source_patch_value != NULL) { - // Using the original source, but not enough free space. First - // copy the source file to cache, then delete it from the original - // location. - - if (strncmp(source_filename, "EMMC:", 5) == 0) { - // It's impossible to free space on the target filesystem by - // deleting the source if the source is a partition. If - // we're ever in a state where we need to do this, fail. - printf("not enough free space for target but source is partition\n"); - return 1; - } - - if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) { - printf("not enough free space on /cache\n"); - return 1; - } - - if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) { - printf("failed to back up source file\n"); - return 1; - } - made_copy = 1; - unlink(source_filename); - - size_t free_space = FreeSpaceForFile(target_fs.c_str()); - printf("(now %zu bytes free for target) ", free_space); - } - } + FileContents* source_to_use; + const Value* patch; + if (source_patch_value != nullptr) { + source_to_use = source_file; + patch = source_patch_value; + } else { + source_to_use = copy_file; + patch = copy_patch_value; + } + if (patch->type != VAL_BLOB) { + printf("patch is not a blob\n"); + return 1; + } - SinkFn sink = NULL; - void* token = NULL; - int output_fd = -1; - if (target_is_partition) { - // We store the decoded output in memory. - sink = MemorySink; - token = &memory_sink_str; - } else { - // We write the decoded output to ".patch". - output_fd = ota_open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, - S_IRUSR | S_IWUSR); - if (output_fd < 0) { - printf("failed to open output file %s: %s\n", tmp_target_filename.c_str(), - strerror(errno)); - return 1; - } - sink = FileSink; - token = &output_fd; - } + const char* header = &patch->data[0]; + size_t header_bytes_read = patch->data.size(); + bool use_bsdiff = false; + if (header_bytes_read >= 8 && memcmp(header, "BSDIFF40", 8) == 0) { + use_bsdiff = true; + } else if (header_bytes_read >= 8 && memcmp(header, "IMGDIFF2", 8) == 0) { + use_bsdiff = false; + } else { + printf("Unknown patch file format\n"); + return 1; + } + bool target_is_partition = (strncmp(target_filename, "EMMC:", 5) == 0); + const std::string tmp_target_filename = std::string(target_filename) + ".patch"; - SHA1_Init(&ctx); + int retry = 1; + bool made_copy = false; + SHA_CTX ctx; + std::string memory_sink_str; // Don't need to reserve space. + do { + // Is there enough room in the target filesystem to hold the patched file? - int result; - if (use_bsdiff) { - result = ApplyBSDiffPatch(source_to_use->data.data(), source_to_use->data.size(), - patch, 0, sink, token, &ctx); - } else { - result = ApplyImagePatch(source_to_use->data.data(), source_to_use->data.size(), - patch, sink, token, &ctx, bonus_data); + if (target_is_partition) { + // If the target is a partition, we're actually going to + // write the output to /tmp and then copy it to the + // partition. statfs() always returns 0 blocks free for + // /tmp, so instead we'll just assume that /tmp has enough + // space to hold the file. + + // We still write the original source to cache, in case + // the partition write is interrupted. + if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) { + printf("not enough free space on /cache\n"); + return 1; + } + if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) { + printf("failed to back up source file\n"); + return 1; + } + made_copy = true; + retry = 0; + } else { + bool enough_space = false; + if (retry > 0) { + size_t free_space = FreeSpaceForFile(target_fs.c_str()); + enough_space = (free_space > (256 << 10)) && // 256k (two-block) minimum + (free_space > (target_size * 3 / 2)); // 50% margin of error + if (!enough_space) { + printf("target %zu bytes; free space %zu bytes; retry %d; enough %d\n", target_size, + free_space, retry, enough_space); } + } + + if (!enough_space) { + retry = 0; + } - if (!target_is_partition) { - if (ota_fsync(output_fd) != 0) { - printf("failed to fsync file \"%s\" (%s)\n", tmp_target_filename.c_str(), - strerror(errno)); - result = 1; - } - if (ota_close(output_fd) != 0) { - printf("failed to close file \"%s\" (%s)\n", tmp_target_filename.c_str(), - strerror(errno)); - result = 1; - } + if (!enough_space && source_patch_value != nullptr) { + // Using the original source, but not enough free space. First + // copy the source file to cache, then delete it from the original + // location. + + if (strncmp(source_filename, "EMMC:", 5) == 0) { + // It's impossible to free space on the target filesystem by + // deleting the source if the source is a partition. If + // we're ever in a state where we need to do this, fail. + printf("not enough free space for target but source is partition\n"); + return 1; } - if (result != 0) { - if (retry == 0) { - printf("applying patch failed\n"); - return result != 0; - } else { - printf("applying patch failed; retrying\n"); - } - if (!target_is_partition) { - unlink(tmp_target_filename.c_str()); - } - } else { - // succeeded; no need to retry - break; + if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) { + printf("not enough free space on /cache\n"); + return 1; } - } while (retry-- > 0); - uint8_t current_target_sha1[SHA_DIGEST_LENGTH]; - SHA1_Final(current_target_sha1, &ctx); - if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_LENGTH) != 0) { - printf("patch did not produce expected sha1\n"); + if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) { + printf("failed to back up source file\n"); + return 1; + } + made_copy = true; + unlink(source_filename); + + size_t free_space = FreeSpaceForFile(target_fs.c_str()); + printf("(now %zu bytes free for target) ", free_space); + } + } + + SinkFn sink = nullptr; + void* token = nullptr; + unique_fd output_fd; + if (target_is_partition) { + // We store the decoded output in memory. + sink = MemorySink; + token = &memory_sink_str; + } else { + // We write the decoded output to ".patch". + output_fd.reset(ota_open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, + S_IRUSR | S_IWUSR)); + if (output_fd == -1) { + printf("failed to open output file %s: %s\n", tmp_target_filename.c_str(), strerror(errno)); return 1; + } + sink = FileSink; + token = &output_fd; + } + + SHA1_Init(&ctx); + + int result; + if (use_bsdiff) { + result = ApplyBSDiffPatch(source_to_use->data.data(), source_to_use->data.size(), patch, 0, + sink, token, &ctx); } else { - printf("now %s\n", short_sha1(target_sha1).c_str()); + result = ApplyImagePatch(source_to_use->data.data(), source_to_use->data.size(), patch, sink, + token, &ctx, bonus_data); } - if (target_is_partition) { - // Copy the temp file to the partition. - if (WriteToPartition(reinterpret_cast(memory_sink_str.c_str()), - memory_sink_str.size(), target_filename) != 0) { - printf("write of patched data to %s failed\n", target_filename); - return 1; - } + if (!target_is_partition) { + if (ota_fsync(output_fd) != 0) { + printf("failed to fsync file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno)); + result = 1; + } + if (ota_close(output_fd) != 0) { + printf("failed to close file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno)); + result = 1; + } + } + + if (result != 0) { + if (retry == 0) { + printf("applying patch failed\n"); + return 1; + } else { + printf("applying patch failed; retrying\n"); + } + if (!target_is_partition) { + unlink(tmp_target_filename.c_str()); + } } else { - // Give the .patch file the same owner, group, and mode of the - // original source file. - if (chmod(tmp_target_filename.c_str(), source_to_use->st.st_mode) != 0) { - printf("chmod of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno)); - return 1; - } - if (chown(tmp_target_filename.c_str(), source_to_use->st.st_uid, source_to_use->st.st_gid) != 0) { - printf("chown of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno)); - return 1; - } + // succeeded; no need to retry + break; + } + } while (retry-- > 0); - // Finally, rename the .patch file to replace the target file. - if (rename(tmp_target_filename.c_str(), target_filename) != 0) { - printf("rename of .patch to \"%s\" failed: %s\n", target_filename, strerror(errno)); - return 1; - } + uint8_t current_target_sha1[SHA_DIGEST_LENGTH]; + SHA1_Final(current_target_sha1, &ctx); + if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_LENGTH) != 0) { + printf("patch did not produce expected sha1\n"); + return 1; + } else { + printf("now %s\n", short_sha1(target_sha1).c_str()); + } + + if (target_is_partition) { + // Copy the temp file to the partition. + if (WriteToPartition(reinterpret_cast(memory_sink_str.c_str()), + memory_sink_str.size(), target_filename) != 0) { + printf("write of patched data to %s failed\n", target_filename); + return 1; + } + } else { + // Give the .patch file the same owner, group, and mode of the original source file. + if (chmod(tmp_target_filename.c_str(), source_to_use->st.st_mode) != 0) { + printf("chmod of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno)); + return 1; + } + if (chown(tmp_target_filename.c_str(), source_to_use->st.st_uid, + source_to_use->st.st_gid) != 0) { + printf("chown of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno)); + return 1; } - // If this run of applypatch created the copy, and we're here, we - // can delete it. - if (made_copy) { - unlink(CACHE_TEMP_SOURCE); + // Finally, rename the .patch file to replace the target file. + if (rename(tmp_target_filename.c_str(), target_filename) != 0) { + printf("rename of .patch to \"%s\" failed: %s\n", target_filename, strerror(errno)); + return 1; } + } - // Success! - return 0; + // If this run of applypatch created the copy, and we're here, we can delete it. + if (made_copy) { + unlink(CACHE_TEMP_SOURCE); + } + + // Success! + return 0; } -- cgit v1.2.3 From 48cf770471ef53fbf0a1837196220862a0bdb18d Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 21 Nov 2016 09:42:33 -0800 Subject: applypatch: Release FD when explicitly calling close. We use android::base::unique_fd() to avoid leaking FD. We also want to call close (or ota_close) to explicitly check the close result. When combining the two together, we need to release the unique_fd to avoid closing the same FD twice. Bug: 33034669 Test: Trigger applypatch with install-recovery.sh. Change-Id: I1a4f5d5fba7a23ef98d8bd7b7b07e87ae6f705c5 --- applypatch/applypatch.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'applypatch/applypatch.cpp') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 9b84fa104..41a8d582b 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -210,7 +210,7 @@ int SaveFileContents(const char* filename, const FileContents* file) { printf("fsync of \"%s\" failed: %s\n", filename, strerror(errno)); return -1; } - if (ota_close(fd) != 0) { + if (ota_close(fd.release()) != 0) { printf("close of \"%s\" failed: %s\n", filename, strerror(errno)); return -1; } @@ -268,7 +268,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const std::string& t printf("failed to sync to %s: %s\n", partition, strerror(errno)); return -1; } - if (ota_close(fd) != 0) { + if (ota_close(fd.release()) != 0) { printf("failed to close %s: %s\n", partition, strerror(errno)); return -1; } @@ -287,7 +287,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const std::string& t } else { printf(" caches dropped\n"); } - ota_close(dc); + ota_close(dc.release()); sleep(1); // Verify. @@ -339,7 +339,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const std::string& t return -1; } - if (ota_close(fd) == -1) { + if (ota_close(fd.release()) == -1) { printf("error closing %s: %s\n", partition, strerror(errno)); return -1; } @@ -782,7 +782,7 @@ static int GenerateTarget(FileContents* source_file, printf("failed to fsync file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno)); result = 1; } - if (ota_close(output_fd) != 0) { + if (ota_close(output_fd.release()) != 0) { printf("failed to close file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno)); result = 1; } -- cgit v1.2.3 From 3dc14cb429061e49ef76948cf55a0e3edf8b170a Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Tue, 22 Nov 2016 11:37:13 -0800 Subject: Add ota_close(unique_fd&) and ota_fclose(std::unique_ptr&). We were using the below sequence prior to the CL in [1]. unique_fd fd(ota_open(...)); ota_close(fd); fd.reset(ota_open(...)); fd.reset() may unintentionally close the newly opened FD if it has the same value as the early ota_open. The CL in [1] changed to "ota_close(fd.release())" to avoid the issue. This CL adds a new overloaded function ota_close(unique_fd&) to handle the release automatically. Similarly add ota_fclose(std::unique_ptr&). [1] commit 48cf770471ef53fbf0a1837196220862a0bdb18d. Bug: 33034669 Test: recovery_component_test passes. Change-Id: Ief91edc590e95a7426e33364b28754173efb1056 --- applypatch/applypatch.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'applypatch/applypatch.cpp') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 41a8d582b..0250407a5 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -66,7 +66,7 @@ int LoadFileContents(const char* filename, FileContents* file) { } std::vector data(file->st.st_size); - std::unique_ptr f(ota_fopen(filename, "rb"), ota_fclose); + std::unique_ptr f(ota_fopen(filename, "rb"), ota_fclose); if (!f) { printf("failed to open \"%s\": %s\n", filename, strerror(errno)); return -1; @@ -118,7 +118,7 @@ static int LoadPartitionContents(const std::string& filename, FileContents* file std::sort(pairs.begin(), pairs.end()); const char* partition = pieces[1].c_str(); - std::unique_ptr dev(ota_fopen(partition, "rb"), ota_fclose); + std::unique_ptr dev(ota_fopen(partition, "rb"), ota_fclose); if (!dev) { printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno)); return -1; @@ -210,7 +210,7 @@ int SaveFileContents(const char* filename, const FileContents* file) { printf("fsync of \"%s\" failed: %s\n", filename, strerror(errno)); return -1; } - if (ota_close(fd.release()) != 0) { + if (ota_close(fd) != 0) { printf("close of \"%s\" failed: %s\n", filename, strerror(errno)); return -1; } @@ -268,7 +268,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const std::string& t printf("failed to sync to %s: %s\n", partition, strerror(errno)); return -1; } - if (ota_close(fd.release()) != 0) { + if (ota_close(fd) != 0) { printf("failed to close %s: %s\n", partition, strerror(errno)); return -1; } @@ -287,7 +287,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const std::string& t } else { printf(" caches dropped\n"); } - ota_close(dc.release()); + ota_close(dc); sleep(1); // Verify. @@ -339,7 +339,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const std::string& t return -1; } - if (ota_close(fd.release()) == -1) { + if (ota_close(fd) == -1) { printf("error closing %s: %s\n", partition, strerror(errno)); return -1; } @@ -782,7 +782,7 @@ static int GenerateTarget(FileContents* source_file, printf("failed to fsync file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno)); result = 1; } - if (ota_close(output_fd.release()) != 0) { + if (ota_close(output_fd) != 0) { printf("failed to close file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno)); result = 1; } -- cgit v1.2.3 From 358c2ec1dca24d48a503b441d38545ace021ea8e Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 28 Nov 2016 11:48:43 -0800 Subject: Remove ota_close(int) and ota_fclose(FILE*). We should always use unique_fd or unique_file to hold the FD or FILE* pointer when opening via ota_(f)open functions. This CL avoids accidentally closing raw FDs or FILE* pointers that are managed by unique_fd/unique_file. Test: recovery_component_test passes. Change-Id: If58eb8b5c5da507563f85efd5d56276472a1c957 --- applypatch/applypatch.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'applypatch/applypatch.cpp') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 0250407a5..95389da6e 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -66,7 +66,7 @@ int LoadFileContents(const char* filename, FileContents* file) { } std::vector data(file->st.st_size); - std::unique_ptr f(ota_fopen(filename, "rb"), ota_fclose); + unique_file f(ota_fopen(filename, "rb")); if (!f) { printf("failed to open \"%s\": %s\n", filename, strerror(errno)); return -1; @@ -118,7 +118,7 @@ static int LoadPartitionContents(const std::string& filename, FileContents* file std::sort(pairs.begin(), pairs.end()); const char* partition = pieces[1].c_str(); - std::unique_ptr dev(ota_fopen(partition, "rb"), ota_fclose); + unique_file dev(ota_fopen(partition, "rb")); if (!dev) { printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno)); return -1; -- cgit v1.2.3 From 9a6f5204190cda6bb6aecb59dff0293cc90ab0b7 Mon Sep 17 00:00:00 2001 From: katao Date: Mon, 19 Dec 2016 11:22:30 +0800 Subject: Bugfix:updater always retry apply patch failed,when memcpy failed. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://code.google.com/p/android/issues/detail?id=230602 On the second attempt, open the file with O_RDONLY, which causing a write failure。 Change-Id: If89165b8c7619fe25722073a46b3cc7c61530a71 Signed-off-by: katao --- applypatch/applypatch.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'applypatch/applypatch.cpp') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 95389da6e..8682e128b 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -332,6 +332,17 @@ int WriteToPartition(const unsigned char* data, size_t len, const std::string& t success = true; break; } + + if (ota_close(fd) != 0) { + printf("failed to close %s: %s\n", partition, strerror(errno)); + return -1; + } + + fd.reset(ota_open(partition, O_RDWR)); + if (fd == -1) { + printf("failed to reopen %s for retry write && verify: %s\n", partition, strerror(errno)); + return -1; + } } if (!success) { -- cgit v1.2.3 From c8e79340e45d4ff423e11db23cdb6aeb3a178585 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 28 Dec 2016 10:11:22 -0800 Subject: applypatch: Don't expose FindMatchingPatch(). Test: make Change-Id: Ic77c4669574b6129e06aa6051804f419bcc8196c --- applypatch/applypatch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'applypatch/applypatch.cpp') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 8682e128b..500663120 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -391,7 +391,7 @@ int ParseSha1(const char* str, uint8_t* digest) { // Search an array of sha1 strings for one matching the given sha1. // Return the index of the match on success, or -1 if no match is // found. -int FindMatchingPatch(uint8_t* sha1, const std::vector& patch_sha1_str) { +static int FindMatchingPatch(uint8_t* sha1, const std::vector& patch_sha1_str) { for (size_t i = 0; i < patch_sha1_str.size(); ++i) { uint8_t patch_sha1[SHA_DIGEST_LENGTH]; if (ParseSha1(patch_sha1_str[i].c_str(), patch_sha1) == 0 && -- cgit v1.2.3 From 40e144dae877654f75e65242535036058ea48f58 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 15 Mar 2017 01:10:58 -0700 Subject: applypatch: Drop the support for patching non-EMMC targets. Patching regular files is used in file-based OTA only, which has become obsolete. Bug: 35853185 Test: Apply an incremental that patches the boot.img. Test: /system/bin/install-recovery.sh works. Test: recovery_component_test passes. Change-Id: Id44e42c4bc63f2162ecc8a6df1cb528b7ae6b0a9 --- applypatch/applypatch.cpp | 386 +++++++++++++--------------------------------- 1 file changed, 109 insertions(+), 277 deletions(-) (limited to 'applypatch/applypatch.cpp') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 500663120..7be3fdbde 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -42,15 +43,9 @@ static int LoadPartitionContents(const std::string& filename, FileContents* file); static ssize_t FileSink(const unsigned char* data, ssize_t len, void* token); -static int GenerateTarget(FileContents* source_file, - const Value* source_patch_value, - FileContents* copy_file, - const Value* copy_patch_value, - const char* source_filename, - const char* target_filename, - const uint8_t target_sha1[SHA_DIGEST_LENGTH], - size_t target_size, - const Value* bonus_data); +static int GenerateTarget(const FileContents& source_file, const std::unique_ptr& patch, + const std::string& target_filename, + const uint8_t target_sha1[SHA_DIGEST_LENGTH], const Value* bonus_data); // Read a file into memory; store the file contents and associated metadata in *file. // Return 0 on success. @@ -190,7 +185,6 @@ static int LoadPartitionContents(const std::string& filename, FileContents* file return 0; } - // Save the contents of the given FileContents object under the given // filename. Return 0 on success. int SaveFileContents(const char* filename, const FileContents* file) { @@ -480,108 +474,90 @@ int CacheSizeCheck(size_t bytes) { } } -// This function applies binary patches to files in a way that is safe -// (the original file is not touched until we have the desired -// replacement for it) and idempotent (it's okay to run this program -// multiple times). +// This function applies binary patches to EMMC target files in a way that is safe (the original +// file is not touched until we have the desired replacement for it) and idempotent (it's okay to +// run this program multiple times). // -// - if the sha1 hash of is , -// does nothing and exits successfully. +// - If the SHA-1 hash of is , does nothing and exits +// successfully. // -// - otherwise, if the sha1 hash of is one of the -// entries in , the corresponding patch from -// (which must be a VAL_BLOB) is applied to produce a -// new file (the type of patch is automatically detected from the -// blob data). If that new file has sha1 hash , -// moves it to replace , and exits successfully. -// Note that if and are not the -// same, is NOT deleted on success. -// may be the string "-" to mean "the same as -// source_filename". +// - Otherwise, if the SHA-1 hash of is one of the entries in , +// the corresponding patch from (which must be a VAL_BLOB) is applied to produce a +// new file (the type of patch is automatically detected from the blob data). If that new file +// has SHA-1 hash , moves it to replace , and exits +// successfully. Note that if and are not the same, +// is NOT deleted on success. may be the string "-" to mean +// "the same as ". // -// - otherwise, or if any error is encountered, exits with non-zero -// status. +// - Otherwise, or if any error is encountered, exits with non-zero status. // -// may refer to a partition to read the source data. -// See the comments for the LoadPartitionContents() function above -// for the format of such a filename. - -int applypatch(const char* source_filename, - const char* target_filename, - const char* target_sha1_str, - size_t target_size, +// must refer to an EMMC partition to read the source data. See the comments for +// the LoadPartitionContents() function above for the format of such a filename. has +// become obsolete since we have dropped the support for patching non-EMMC targets (EMMC targets +// have the size embedded in the filename). +int applypatch(const char* source_filename, const char* target_filename, + const char* target_sha1_str, size_t target_size __unused, const std::vector& patch_sha1_str, - const std::vector>& patch_data, - const Value* bonus_data) { - printf("patch %s: ", source_filename); + const std::vector>& patch_data, const Value* bonus_data) { + printf("patch %s: ", source_filename); - if (target_filename[0] == '-' && target_filename[1] == '\0') { - target_filename = source_filename; - } + if (target_filename[0] == '-' && target_filename[1] == '\0') { + target_filename = source_filename; + } - uint8_t target_sha1[SHA_DIGEST_LENGTH]; - if (ParseSha1(target_sha1_str, target_sha1) != 0) { - printf("failed to parse tgt-sha1 \"%s\"\n", target_sha1_str); - return 1; - } + if (strncmp(target_filename, "EMMC:", 5) != 0) { + printf("Supporting patching EMMC targets only.\n"); + return 1; + } - FileContents source_file; - const Value* source_patch_value = nullptr; + uint8_t target_sha1[SHA_DIGEST_LENGTH]; + if (ParseSha1(target_sha1_str, target_sha1) != 0) { + printf("failed to parse tgt-sha1 \"%s\"\n", target_sha1_str); + return 1; + } - // We try to load the target file into the source_file object. - if (LoadFileContents(target_filename, &source_file) == 0) { - if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_LENGTH) == 0) { - // The early-exit case: the patch was already applied, this file - // has the desired hash, nothing for us to do. - printf("already %s\n", short_sha1(target_sha1).c_str()); - return 0; - } + // We try to load the target file into the source_file object. + FileContents source_file; + if (LoadFileContents(target_filename, &source_file) == 0) { + if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_LENGTH) == 0) { + // The early-exit case: the patch was already applied, this file has the desired hash, nothing + // for us to do. + printf("already %s\n", short_sha1(target_sha1).c_str()); + return 0; } + } - if (source_file.data.empty() || - (target_filename != source_filename && - strcmp(target_filename, source_filename) != 0)) { - // Need to load the source file: either we failed to load the - // target file, or we did but it's different from the source file. - source_file.data.clear(); - LoadFileContents(source_filename, &source_file); - } + if (source_file.data.empty() || + (target_filename != source_filename && strcmp(target_filename, source_filename) != 0)) { + // Need to load the source file: either we failed to load the target file, or we did but it's + // different from the expected. + source_file.data.clear(); + LoadFileContents(source_filename, &source_file); + } - if (!source_file.data.empty()) { - int to_use = FindMatchingPatch(source_file.sha1, patch_sha1_str); - if (to_use >= 0) { - source_patch_value = patch_data[to_use].get(); - } + if (!source_file.data.empty()) { + int to_use = FindMatchingPatch(source_file.sha1, patch_sha1_str); + if (to_use != -1) { + return GenerateTarget(source_file, patch_data[to_use], target_filename, target_sha1, + bonus_data); } + } - FileContents copy_file; - const Value* copy_patch_value = nullptr; - if (source_patch_value == nullptr) { - source_file.data.clear(); - printf("source file is bad; trying copy\n"); - - if (LoadFileContents(CACHE_TEMP_SOURCE, ©_file) < 0) { - // fail. - printf("failed to read copy file\n"); - return 1; - } + printf("source file is bad; trying copy\n"); - int to_use = FindMatchingPatch(copy_file.sha1, patch_sha1_str); - if (to_use >= 0) { - copy_patch_value = patch_data[to_use].get(); - } + FileContents copy_file; + if (LoadFileContents(CACHE_TEMP_SOURCE, ©_file) < 0) { + printf("failed to read copy file\n"); + return 1; + } - if (copy_patch_value == nullptr) { - // fail. - printf("copy file doesn't match source SHA-1s either\n"); - return 1; - } - } + int to_use = FindMatchingPatch(copy_file.sha1, patch_sha1_str); + if (to_use == -1) { + printf("copy file doesn't match source SHA-1s either\n"); + return 1; + } - return GenerateTarget(&source_file, source_patch_value, - ©_file, copy_patch_value, - source_filename, target_filename, - target_sha1, target_size, bonus_data); + return GenerateTarget(copy_file, patch_data[to_use], target_filename, target_sha1, bonus_data); } /* @@ -638,34 +614,9 @@ int applypatch_flash(const char* source_filename, const char* target_filename, return 0; } -static int GenerateTarget(FileContents* source_file, - const Value* source_patch_value, - FileContents* copy_file, - const Value* copy_patch_value, - const char* source_filename, - const char* target_filename, - const uint8_t target_sha1[SHA_DIGEST_LENGTH], - size_t target_size, - const Value* bonus_data) { - // assume that target_filename (eg "/system/app/Foo.apk") is located - // on the same filesystem as its top-level directory ("/system"). - // We need something that exists for calling statfs(). - std::string target_fs = target_filename; - auto slash_pos = target_fs.find('/', 1); - if (slash_pos != std::string::npos) { - target_fs.resize(slash_pos); - } - - FileContents* source_to_use; - const Value* patch; - if (source_patch_value != nullptr) { - source_to_use = source_file; - patch = source_patch_value; - } else { - source_to_use = copy_file; - patch = copy_patch_value; - } - +static int GenerateTarget(const FileContents& source_file, const std::unique_ptr& patch, + const std::string& target_filename, + const uint8_t target_sha1[SHA_DIGEST_LENGTH], const Value* bonus_data) { if (patch->type != VAL_BLOB) { printf("patch is not a blob\n"); return 1; @@ -683,137 +634,39 @@ static int GenerateTarget(FileContents* source_file, return 1; } - bool target_is_partition = (strncmp(target_filename, "EMMC:", 5) == 0); - const std::string tmp_target_filename = std::string(target_filename) + ".patch"; - - int retry = 1; - bool made_copy = false; - SHA_CTX ctx; - std::string memory_sink_str; // Don't need to reserve space. - do { - // Is there enough room in the target filesystem to hold the patched file? - - if (target_is_partition) { - // If the target is a partition, we're actually going to - // write the output to /tmp and then copy it to the - // partition. statfs() always returns 0 blocks free for - // /tmp, so instead we'll just assume that /tmp has enough - // space to hold the file. - - // We still write the original source to cache, in case - // the partition write is interrupted. - if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) { - printf("not enough free space on /cache\n"); - return 1; - } - if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) { - printf("failed to back up source file\n"); - return 1; - } - made_copy = true; - retry = 0; - } else { - bool enough_space = false; - if (retry > 0) { - size_t free_space = FreeSpaceForFile(target_fs.c_str()); - enough_space = (free_space > (256 << 10)) && // 256k (two-block) minimum - (free_space > (target_size * 3 / 2)); // 50% margin of error - if (!enough_space) { - printf("target %zu bytes; free space %zu bytes; retry %d; enough %d\n", target_size, - free_space, retry, enough_space); - } - } - - if (!enough_space) { - retry = 0; - } - - if (!enough_space && source_patch_value != nullptr) { - // Using the original source, but not enough free space. First - // copy the source file to cache, then delete it from the original - // location. - - if (strncmp(source_filename, "EMMC:", 5) == 0) { - // It's impossible to free space on the target filesystem by - // deleting the source if the source is a partition. If - // we're ever in a state where we need to do this, fail. - printf("not enough free space for target but source is partition\n"); - return 1; - } + CHECK(android::base::StartsWith(target_filename, "EMMC:")); - if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) { - printf("not enough free space on /cache\n"); - return 1; - } - - if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) { - printf("failed to back up source file\n"); - return 1; - } - made_copy = true; - unlink(source_filename); - - size_t free_space = FreeSpaceForFile(target_fs.c_str()); - printf("(now %zu bytes free for target) ", free_space); - } - } - - SinkFn sink = nullptr; - void* token = nullptr; - unique_fd output_fd; - if (target_is_partition) { - // We store the decoded output in memory. - sink = MemorySink; - token = &memory_sink_str; - } else { - // We write the decoded output to ".patch". - output_fd.reset(ota_open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, - S_IRUSR | S_IWUSR)); - if (output_fd == -1) { - printf("failed to open output file %s: %s\n", tmp_target_filename.c_str(), strerror(errno)); - return 1; - } - sink = FileSink; - token = &output_fd; - } + // We still write the original source to cache, in case the partition write is interrupted. + if (MakeFreeSpaceOnCache(source_file.data.size()) < 0) { + printf("not enough free space on /cache\n"); + return 1; + } + if (SaveFileContents(CACHE_TEMP_SOURCE, &source_file) < 0) { + printf("failed to back up source file\n"); + return 1; + } - SHA1_Init(&ctx); + // We store the decoded output in memory. + SinkFn sink = MemorySink; + std::string memory_sink_str; // Don't need to reserve space. + void* token = &memory_sink_str; - int result; - if (use_bsdiff) { - result = ApplyBSDiffPatch(source_to_use->data.data(), source_to_use->data.size(), patch, 0, - sink, token, &ctx); - } else { - result = ApplyImagePatch(source_to_use->data.data(), source_to_use->data.size(), patch, sink, - token, &ctx, bonus_data); - } + SHA_CTX ctx; + SHA1_Init(&ctx); - if (!target_is_partition) { - if (ota_fsync(output_fd) != 0) { - printf("failed to fsync file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno)); - result = 1; - } - if (ota_close(output_fd) != 0) { - printf("failed to close file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno)); - result = 1; - } - } + int result; + if (use_bsdiff) { + result = ApplyBSDiffPatch(source_file.data.data(), source_file.data.size(), patch.get(), 0, + sink, token, &ctx); + } else { + result = ApplyImagePatch(source_file.data.data(), source_file.data.size(), patch.get(), sink, + token, &ctx, bonus_data); + } - if (result != 0) { - if (retry == 0) { - printf("applying patch failed\n"); - return 1; - } else { - printf("applying patch failed; retrying\n"); - } - if (!target_is_partition) { - unlink(tmp_target_filename.c_str()); - } - } else { - // succeeded; no need to retry - break; - } - } while (retry-- > 0); + if (result != 0) { + printf("applying patch failed\n"); + return 1; + } uint8_t current_target_sha1[SHA_DIGEST_LENGTH]; SHA1_Final(current_target_sha1, &ctx); @@ -824,36 +677,15 @@ static int GenerateTarget(FileContents* source_file, printf("now %s\n", short_sha1(target_sha1).c_str()); } - if (target_is_partition) { - // Copy the temp file to the partition. - if (WriteToPartition(reinterpret_cast(memory_sink_str.c_str()), - memory_sink_str.size(), target_filename) != 0) { - printf("write of patched data to %s failed\n", target_filename); - return 1; - } - } else { - // Give the .patch file the same owner, group, and mode of the original source file. - if (chmod(tmp_target_filename.c_str(), source_to_use->st.st_mode) != 0) { - printf("chmod of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno)); - return 1; - } - if (chown(tmp_target_filename.c_str(), source_to_use->st.st_uid, - source_to_use->st.st_gid) != 0) { - printf("chown of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno)); - return 1; - } - - // Finally, rename the .patch file to replace the target file. - if (rename(tmp_target_filename.c_str(), target_filename) != 0) { - printf("rename of .patch to \"%s\" failed: %s\n", target_filename, strerror(errno)); - return 1; - } + // Write back the temp file to the partition. + if (WriteToPartition(reinterpret_cast(memory_sink_str.c_str()), + memory_sink_str.size(), target_filename) != 0) { + printf("write of patched data to %s failed\n", target_filename.c_str()); + return 1; } - // If this run of applypatch created the copy, and we're here, we can delete it. - if (made_copy) { - unlink(CACHE_TEMP_SOURCE); - } + // Delete the backup copy of the source. + unlink(CACHE_TEMP_SOURCE); // Success! return 0; -- cgit v1.2.3