diff options
-rw-r--r-- | Android.mk | 20 | ||||
-rw-r--r-- | README.md | 17 | ||||
-rw-r--r-- | applypatch/Android.mk | 10 | ||||
-rw-r--r-- | applypatch/applypatch.cpp | 226 | ||||
-rw-r--r-- | applypatch/applypatch.h | 17 | ||||
-rw-r--r-- | applypatch/bspatch.cpp | 39 | ||||
-rw-r--r-- | applypatch/freecache.cpp | 141 | ||||
-rw-r--r-- | applypatch/imgpatch.cpp | 60 | ||||
-rw-r--r-- | applypatch/main.cpp | 83 | ||||
-rw-r--r-- | print_sha1.h | 10 | ||||
-rw-r--r-- | tests/Android.mk | 35 | ||||
-rw-r--r-- | tests/component/verifier_test.cpp (renamed from verifier_test.cpp) | 167 | ||||
-rw-r--r-- | tests/testdata/alter-footer.zip (renamed from testdata/alter-footer.zip) | bin | 4009 -> 4009 bytes | |||
-rw-r--r-- | tests/testdata/alter-metadata.zip (renamed from testdata/alter-metadata.zip) | bin | 4009 -> 4009 bytes | |||
-rw-r--r-- | tests/testdata/fake-eocd.zip (renamed from testdata/fake-eocd.zip) | bin | 4313 -> 4313 bytes | |||
-rw-r--r-- | tests/testdata/jarsigned.zip (renamed from testdata/jarsigned.zip) | bin | 2271 -> 2271 bytes | |||
-rw-r--r-- | tests/testdata/otasigned.zip (renamed from testdata/otasigned.zip) | bin | 4009 -> 4009 bytes | |||
-rw-r--r-- | tests/testdata/otasigned_ecdsa_sha256.zip (renamed from testdata/otasigned_ecdsa_sha256.zip) | bin | 3085 -> 3085 bytes | |||
-rw-r--r-- | tests/testdata/otasigned_f4.zip (renamed from testdata/otasigned_f4.zip) | bin | 5195 -> 5195 bytes | |||
-rw-r--r-- | tests/testdata/otasigned_f4_sha256.zip (renamed from testdata/otasigned_f4_sha256.zip) | bin | 5319 -> 5319 bytes | |||
-rw-r--r-- | tests/testdata/otasigned_sha256.zip (renamed from testdata/otasigned_sha256.zip) | bin | 5326 -> 5326 bytes | |||
-rw-r--r-- | tests/testdata/random.zip (renamed from testdata/random.zip) | bin | 1024 -> 1024 bytes | |||
-rw-r--r-- | tests/testdata/test_f4.pk8 (renamed from testdata/test_f4.pk8) | bin | 1217 -> 1217 bytes | |||
-rw-r--r-- | tests/testdata/test_f4.x509.pem (renamed from testdata/test_f4.x509.pem) | 0 | ||||
-rw-r--r-- | tests/testdata/test_f4_sha256.x509.pem (renamed from testdata/test_f4_sha256.x509.pem) | 0 | ||||
-rw-r--r-- | tests/testdata/testkey.pk8 (renamed from testdata/testkey.pk8) | bin | 1217 -> 1217 bytes | |||
-rw-r--r-- | tests/testdata/testkey.x509.pem (renamed from testdata/testkey.x509.pem) | 0 | ||||
-rw-r--r-- | tests/testdata/testkey_ecdsa.pk8 (renamed from testdata/testkey_ecdsa.pk8) | bin | 138 -> 138 bytes | |||
-rw-r--r-- | tests/testdata/testkey_ecdsa.x509.pem (renamed from testdata/testkey_ecdsa.x509.pem) | 0 | ||||
-rw-r--r-- | tests/testdata/testkey_sha256.x509.pem (renamed from testdata/testkey_sha256.x509.pem) | 0 | ||||
-rw-r--r-- | tests/testdata/unsigned.zip (renamed from testdata/unsigned.zip) | bin | 376 -> 376 bytes | |||
-rw-r--r-- | tests/unit/asn1_decoder_test.cpp (renamed from tests/asn1_decoder_test.cpp) | 0 | ||||
-rw-r--r-- | updater/Android.mk | 2 | ||||
-rw-r--r-- | updater/blockimg.cpp | 19 | ||||
-rw-r--r-- | updater/install.cpp | 95 | ||||
-rwxr-xr-x | verifier_test.sh | 121 |
36 files changed, 443 insertions, 619 deletions
diff --git a/Android.mk b/Android.mk index 13fc04bcc..4da34eef5 100644 --- a/Android.mk +++ b/Android.mk @@ -104,28 +104,10 @@ LOCAL_CLANG := true LOCAL_MODULE := libverifier LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := \ - asn1_decoder.cpp -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) -LOCAL_CLANG := true -LOCAL_MODULE := verifier_test -LOCAL_FORCE_STATIC_EXECUTABLE := true -LOCAL_MODULE_TAGS := tests -LOCAL_CFLAGS += -Wno-unused-parameter -LOCAL_SRC_FILES := \ - verifier_test.cpp \ asn1_decoder.cpp \ verifier.cpp \ ui.cpp -LOCAL_STATIC_LIBRARIES := \ - libmincrypt \ - libminui \ - libminzip \ - libcutils \ - libc -include $(BUILD_EXECUTABLE) - +include $(BUILD_STATIC_LIBRARY) include $(LOCAL_PATH)/minui/Android.mk \ $(LOCAL_PATH)/minzip/Android.mk \ @@ -10,3 +10,20 @@ Quick turn-around testing # without flashing the recovery partition: adb reboot bootloader fastboot boot $ANDROID_PRODUCT_OUT/recovery.img + +Running the tests +----------------- + # After setting up environment and lunch. + mmma -j bootable/recovery + + # Running the tests on device. + adb root + adb sync data + + # 32-bit device + adb shell /data/nativetest/recovery_unit_test/recovery_unit_test + adb shell /data/nativetest/recovery_component_test/recovery_component_test + + # Or 64-bit device + adb shell /data/nativetest64/recovery_unit_test/recovery_unit_test + adb shell /data/nativetest64/recovery_component_test/recovery_component_test diff --git a/applypatch/Android.mk b/applypatch/Android.mk index bc2e69e62..887a570db 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -21,7 +21,7 @@ LOCAL_SRC_FILES := applypatch.cpp bspatch.cpp freecache.cpp imgpatch.cpp utils.c LOCAL_MODULE := libapplypatch LOCAL_MODULE_TAGS := eng LOCAL_C_INCLUDES += bootable/recovery -LOCAL_STATIC_LIBRARIES += libbase libotafault libmtdutils libmincrypt libbz libz +LOCAL_STATIC_LIBRARIES += libbase libotafault libmtdutils libcrypto_static libbz libz include $(BUILD_STATIC_LIBRARY) @@ -32,7 +32,7 @@ LOCAL_SRC_FILES := bspatch.cpp imgpatch.cpp utils.cpp LOCAL_MODULE := libimgpatch LOCAL_C_INCLUDES += bootable/recovery LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include -LOCAL_STATIC_LIBRARIES += libmincrypt libbz libz +LOCAL_STATIC_LIBRARIES += libcrypto_static libbz libz include $(BUILD_STATIC_LIBRARY) @@ -44,7 +44,7 @@ LOCAL_SRC_FILES := bspatch.cpp imgpatch.cpp utils.cpp LOCAL_MODULE := libimgpatch LOCAL_C_INCLUDES += bootable/recovery LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include -LOCAL_STATIC_LIBRARIES += libmincrypt libbz libz +LOCAL_STATIC_LIBRARIES += libcrypto_static libbz libz include $(BUILD_HOST_STATIC_LIBRARY) endif # HOST_OS == linux @@ -55,7 +55,9 @@ LOCAL_CLANG := true LOCAL_SRC_FILES := main.cpp LOCAL_MODULE := applypatch LOCAL_C_INCLUDES += bootable/recovery -LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libmtdutils libmincrypt libbz +LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libmtdutils libcrypto_static libbz \ + libedify \ + LOCAL_SHARED_LIBRARIES += libz libcutils libc include $(BUILD_EXECUTABLE) diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 93e6b25ac..9f5e2f200 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -25,9 +25,12 @@ #include <sys/types.h> #include <unistd.h> +#include <memory> +#include <string> + #include <android-base/strings.h> -#include "mincrypt/sha.h" +#include "openssl/sha.h" #include "applypatch.h" #include "mtdutils/mtdutils.h" #include "edify/expr.h" @@ -42,7 +45,7 @@ static int GenerateTarget(FileContents* source_file, const Value* copy_patch_value, const char* source_filename, const char* target_filename, - const uint8_t target_sha1[SHA_DIGEST_SIZE], + const uint8_t target_sha1[SHA_DIGEST_LENGTH], size_t target_size, const Value* bonus_data); @@ -68,26 +71,30 @@ int LoadFileContents(const char* filename, FileContents* file) { } file->size = file->st.st_size; - file->data = reinterpret_cast<unsigned char*>(malloc(file->size)); + file->data = nullptr; + + std::unique_ptr<unsigned char, decltype(&free)> data( + static_cast<unsigned char*>(malloc(file->size)), free); + if (data == nullptr) { + printf("failed to allocate memory: %s\n", strerror(errno)); + return -1; + } FILE* f = ota_fopen(filename, "rb"); if (f == NULL) { printf("failed to open \"%s\": %s\n", filename, strerror(errno)); - free(file->data); - file->data = NULL; return -1; } - size_t bytes_read = ota_fread(file->data, 1, file->size, f); + size_t bytes_read = ota_fread(data.get(), 1, file->size, f); if (bytes_read != static_cast<size_t>(file->size)) { printf("short read of \"%s\" (%zu bytes of %zd)\n", filename, bytes_read, file->size); - free(file->data); - file->data = NULL; + fclose(f); return -1; } ota_fclose(f); - - SHA_hash(file->data, file->size, file->sha1); + file->data = data.release(); + SHA1(file->data, file->size, file->sha1); return 0; } @@ -182,11 +189,11 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { } SHA_CTX sha_ctx; - SHA_init(&sha_ctx); - uint8_t parsed_sha[SHA_DIGEST_SIZE]; + SHA1_Init(&sha_ctx); + uint8_t parsed_sha[SHA_DIGEST_LENGTH]; // Allocate enough memory to hold the largest size. - file->data = reinterpret_cast<unsigned char*>(malloc(size[index[pairs-1]])); + file->data = static_cast<unsigned char*>(malloc(size[index[pairs-1]])); char* p = (char*)file->data; file->size = 0; // # bytes read so far bool found = false; @@ -213,7 +220,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { file->data = NULL; return -1; } - SHA_update(&sha_ctx, p, read); + SHA1_Update(&sha_ctx, p, read); file->size += read; } @@ -221,7 +228,8 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { // check it against this pair's expected hash. SHA_CTX temp_ctx; memcpy(&temp_ctx, &sha_ctx, sizeof(SHA_CTX)); - const uint8_t* sha_so_far = SHA_final(&temp_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); @@ -230,7 +238,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { return -1; } - if (memcmp(sha_so_far, parsed_sha, SHA_DIGEST_SIZE) == 0) { + 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", @@ -261,10 +269,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { return -1; } - const uint8_t* sha_final = SHA_final(&sha_ctx); - for (size_t i = 0; i < SHA_DIGEST_SIZE; ++i) { - file->sha1[i] = sha_final[i]; - } + SHA1_Final(file->sha1, &sha_ctx); // Fake some stat() info. file->st.st_mode = 0644; @@ -316,7 +321,7 @@ int SaveFileContents(const char* filename, const FileContents* file) { // "MTD:<partition>[:...]" or "EMMC:<partition_device>[:...]". The target name // might contain multiple colons, but WriteToPartition() only uses the first // two and ignores the rest. Return 0 on success. -int WriteToPartition(unsigned char* data, size_t len, const char* target) { +int WriteToPartition(const unsigned char* data, size_t len, const char* target) { std::string copy(target); std::vector<std::string> pieces = android::base::Split(copy, ":"); @@ -355,7 +360,7 @@ int WriteToPartition(unsigned char* data, size_t len, const char* target) { return -1; } - size_t written = mtd_write_data(ctx, reinterpret_cast<char*>(data), len); + size_t written = mtd_write_data(ctx, reinterpret_cast<const char*>(data), len); if (written != len) { printf("only wrote %zu of %zu bytes to MTD %s\n", written, len, partition); mtd_write_close(ctx); @@ -495,7 +500,7 @@ int WriteToPartition(unsigned char* data, size_t len, const char* target) { int ParseSha1(const char* str, uint8_t* digest) { const char* ps = str; uint8_t* pd = digest; - for (int i = 0; i < SHA_DIGEST_SIZE * 2; ++i, ++ps) { + for (int i = 0; i < SHA_DIGEST_LENGTH * 2; ++i, ++ps) { int digit; if (*ps >= '0' && *ps <= '9') { digit = *ps - '0'; @@ -522,10 +527,10 @@ int ParseSha1(const char* str, uint8_t* digest) { // found. int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str, int num_patches) { - uint8_t patch_sha1[SHA_DIGEST_SIZE]; + uint8_t patch_sha1[SHA_DIGEST_LENGTH]; for (int i = 0; i < num_patches; ++i) { if (ParseSha1(patch_sha1_str[i], patch_sha1) == 0 && - memcmp(patch_sha1, sha1, SHA_DIGEST_SIZE) == 0) { + memcmp(patch_sha1, sha1, SHA_DIGEST_LENGTH) == 0) { return i; } } @@ -581,7 +586,7 @@ int ShowLicenses() { } ssize_t FileSink(const unsigned char* data, ssize_t len, void* token) { - int fd = *reinterpret_cast<int *>(token); + int fd = *static_cast<int*>(token); ssize_t done = 0; ssize_t wrote; while (done < len) { @@ -595,19 +600,9 @@ ssize_t FileSink(const unsigned char* data, ssize_t len, void* token) { return done; } -typedef struct { - unsigned char* buffer; - ssize_t size; - ssize_t pos; -} MemorySinkInfo; - ssize_t MemorySink(const unsigned char* data, ssize_t len, void* token) { - MemorySinkInfo* msi = reinterpret_cast<MemorySinkInfo*>(token); - if (msi->size - msi->pos < len) { - return -1; - } - memcpy(msi->buffer + msi->pos, data, len); - msi->pos += len; + std::string* s = static_cast<std::string*>(token); + s->append(reinterpret_cast<const char*>(data), len); return len; } @@ -671,7 +666,7 @@ int applypatch(const char* source_filename, target_filename = source_filename; } - uint8_t target_sha1[SHA_DIGEST_SIZE]; + 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; @@ -686,7 +681,7 @@ int applypatch(const char* source_filename, // 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_SIZE) == 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()); @@ -757,7 +752,7 @@ 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); - uint8_t target_sha1[SHA_DIGEST_SIZE]; + 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; @@ -778,7 +773,7 @@ int applypatch_flash(const char* source_filename, const char* target_filename, pieces.push_back(target_sha1_str); std::string fullname = android::base::Join(pieces, ':'); if (LoadPartitionContents(fullname.c_str(), &source_file) == 0 && - memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 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()); @@ -787,7 +782,7 @@ int applypatch_flash(const char* source_filename, const char* target_filename, } if (LoadFileContents(source_filename, &source_file) == 0) { - if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE) != 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(), @@ -813,36 +808,57 @@ static int GenerateTarget(FileContents* source_file, const Value* copy_patch_value, const char* source_filename, const char* target_filename, - const uint8_t target_sha1[SHA_DIGEST_SIZE], + const uint8_t target_sha1[SHA_DIGEST_LENGTH], size_t target_size, const Value* bonus_data) { int retry = 1; SHA_CTX ctx; - int output; - MemorySinkInfo msi; + std::string memory_sink_str; FileContents* source_to_use; - char* outname; int made_copy = 0; + bool target_is_partition = (strncmp(target_filename, "MTD:", 4) == 0 || + 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(). - char target_fs[strlen(target_filename)+1]; - char* slash = strchr(target_filename+1, '/'); - if (slash != NULL) { - int count = slash - target_filename; - strncpy(target_fs, target_filename, count); - target_fs[count] = '\0'; + 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 { - strcpy(target_fs, target_filename); + source_to_use = copy_file; + patch = copy_patch_value; + } + if (patch->type != VAL_BLOB) { + printf("patch is not a blob\n"); + return 1; + } + char* header = patch->data; + ssize_t header_bytes_read = patch->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; } do { // Is there enough room in the target filesystem to hold the patched // file? - if (strncmp(target_filename, "MTD:", 4) == 0 || - strncmp(target_filename, "EMMC:", 5) == 0) { + 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 @@ -864,7 +880,7 @@ static int GenerateTarget(FileContents* source_file, } else { int enough_space = 0; if (retry > 0) { - size_t free_space = FreeSpaceForFile(target_fs); + 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 @@ -904,84 +920,53 @@ static int GenerateTarget(FileContents* source_file, made_copy = 1; unlink(source_filename); - size_t free_space = FreeSpaceForFile(target_fs); + size_t free_space = FreeSpaceForFile(target_fs.c_str()); printf("(now %zu bytes free for target) ", free_space); } } - 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; - } SinkFn sink = NULL; void* token = NULL; - output = -1; - outname = NULL; - if (strncmp(target_filename, "MTD:", 4) == 0 || - strncmp(target_filename, "EMMC:", 5) == 0) { + int output_fd = -1; + if (target_is_partition) { // We store the decoded output in memory. - msi.buffer = reinterpret_cast<unsigned char*>(malloc(target_size)); - if (msi.buffer == NULL) { - printf("failed to alloc %zu bytes for output\n", target_size); - return 1; - } - msi.pos = 0; - msi.size = target_size; sink = MemorySink; - token = &msi; + token = &memory_sink_str; } else { // We write the decoded output to "<tgt-file>.patch". - outname = reinterpret_cast<char*>(malloc(strlen(target_filename) + 10)); - strcpy(outname, target_filename); - strcat(outname, ".patch"); - - output = ota_open(outname, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR); - if (output < 0) { - printf("failed to open output file %s: %s\n", - outname, strerror(errno)); + 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; + token = &output_fd; } - char* header = patch->data; - ssize_t header_bytes_read = patch->size; - SHA_init(&ctx); + SHA1_Init(&ctx); int result; - - if (header_bytes_read >= 8 && - memcmp(header, "BSDIFF40", 8) == 0) { + if (use_bsdiff) { result = ApplyBSDiffPatch(source_to_use->data, source_to_use->size, patch, 0, sink, token, &ctx); - } else if (header_bytes_read >= 8 && - memcmp(header, "IMGDIFF2", 8) == 0) { + } else { result = ApplyImagePatch(source_to_use->data, source_to_use->size, patch, sink, token, &ctx, bonus_data); - } else { - printf("Unknown patch file format\n"); - return 1; } - if (output >= 0) { - if (ota_fsync(output) != 0) { - printf("failed to fsync file \"%s\" (%s)\n", outname, strerror(errno)); + 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) != 0) { - printf("failed to close file \"%s\" (%s)\n", outname, strerror(errno)); + if (ota_close(output_fd) != 0) { + printf("failed to close file \"%s\" (%s)\n", tmp_target_filename.c_str(), + strerror(errno)); result = 1; } } @@ -993,8 +978,8 @@ static int GenerateTarget(FileContents* source_file, } else { printf("applying patch failed; retrying\n"); } - if (outname != NULL) { - unlink(outname); + if (!target_is_partition) { + unlink(tmp_target_filename.c_str()); } } else { // succeeded; no need to retry @@ -1002,35 +987,36 @@ static int GenerateTarget(FileContents* source_file, } } while (retry-- > 0); - const uint8_t* current_target_sha1 = SHA_final(&ctx); - if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_SIZE) != 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"); return 1; } else { printf("now %s\n", short_sha1(target_sha1).c_str()); } - if (output < 0) { + if (target_is_partition) { // Copy the temp file to the partition. - if (WriteToPartition(msi.buffer, msi.pos, target_filename) != 0) { + if (WriteToPartition(reinterpret_cast<const unsigned char*>(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; } - free(msi.buffer); } else { // Give the .patch file the same owner, group, and mode of the // original source file. - if (chmod(outname, source_to_use->st.st_mode) != 0) { - printf("chmod of \"%s\" failed: %s\n", outname, strerror(errno)); + 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(outname, source_to_use->st.st_uid, source_to_use->st.st_gid) != 0) { - printf("chown of \"%s\" failed: %s\n", outname, strerror(errno)); + 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(outname, target_filename) != 0) { + 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; } diff --git a/applypatch/applypatch.h b/applypatch/applypatch.h index 415bc1b3c..14fb490ba 100644 --- a/applypatch/applypatch.h +++ b/applypatch/applypatch.h @@ -18,16 +18,19 @@ #define _APPLYPATCH_H #include <sys/stat.h> -#include "mincrypt/sha.h" + +#include <vector> + +#include "openssl/sha.h" #include "edify/expr.h" typedef struct _Patch { - uint8_t sha1[SHA_DIGEST_SIZE]; + uint8_t sha1[SHA_DIGEST_LENGTH]; const char* patch_filename; } Patch; typedef struct _FileContents { - uint8_t sha1[SHA_DIGEST_SIZE]; + uint8_t sha1[SHA_DIGEST_LENGTH]; unsigned char* data; ssize_t size; struct stat st; @@ -68,22 +71,22 @@ void FreeFileContents(FileContents* file); int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str, int num_patches); -// bsdiff.c +// bsdiff.cpp void ShowBSDiffLicense(); int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size, const Value* patch, ssize_t patch_offset, SinkFn sink, void* token, SHA_CTX* ctx); int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, const Value* patch, ssize_t patch_offset, - unsigned char** new_data, ssize_t* new_size); + std::vector<unsigned char>* new_data); -// imgpatch.c +// imgpatch.cpp int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, const Value* patch, SinkFn sink, void* token, SHA_CTX* ctx, const Value* bonus_data); -// freecache.c +// freecache.cpp int MakeFreeSpaceOnCache(size_t bytes_needed); #endif diff --git a/applypatch/bspatch.cpp b/applypatch/bspatch.cpp index 75975ad6d..ebb55f1d1 100644 --- a/applypatch/bspatch.cpp +++ b/applypatch/bspatch.cpp @@ -24,13 +24,12 @@ #include <sys/stat.h> #include <sys/types.h> #include <errno.h> -#include <malloc.h> #include <unistd.h> #include <string.h> #include <bzlib.h> -#include "mincrypt/sha.h" +#include "openssl/sha.h" #include "applypatch.h" void ShowBSDiffLicense() { @@ -103,26 +102,22 @@ int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size, const Value* patch, ssize_t patch_offset, SinkFn sink, void* token, SHA_CTX* ctx) { - unsigned char* new_data; - ssize_t new_size; - if (ApplyBSDiffPatchMem(old_data, old_size, patch, patch_offset, - &new_data, &new_size) != 0) { + std::vector<unsigned char> new_data; + if (ApplyBSDiffPatchMem(old_data, old_size, patch, patch_offset, &new_data) != 0) { return -1; } - if (sink(new_data, new_size, token) < new_size) { + if (sink(new_data.data(), new_data.size(), token) < static_cast<ssize_t>(new_data.size())) { printf("short write of output: %d (%s)\n", errno, strerror(errno)); return 1; } - if (ctx) SHA_update(ctx, new_data, new_size); - free(new_data); - + if (ctx) SHA1_Update(ctx, new_data.data(), new_data.size()); return 0; } int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, const Value* patch, ssize_t patch_offset, - unsigned char** new_data, ssize_t* new_size) { + std::vector<unsigned char>* new_data) { // Patch data format: // 0 8 "BSDIFF40" // 8 8 X @@ -141,12 +136,12 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, return 1; } - ssize_t ctrl_len, data_len; + ssize_t ctrl_len, data_len, new_size; ctrl_len = offtin(header+8); data_len = offtin(header+16); - *new_size = offtin(header+24); + new_size = offtin(header+24); - if (ctrl_len < 0 || data_len < 0 || *new_size < 0) { + if (ctrl_len < 0 || data_len < 0 || new_size < 0) { printf("corrupt patch file header (data lengths)\n"); return 1; } @@ -183,18 +178,14 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, printf("failed to bzinit extra stream (%d)\n", bzerr); } - *new_data = reinterpret_cast<unsigned char*>(malloc(*new_size)); - if (*new_data == NULL) { - printf("failed to allocate %zd bytes of memory for output file\n", *new_size); - return 1; - } + new_data->resize(new_size); off_t oldpos = 0, newpos = 0; off_t ctrl[3]; off_t len_read; int i; unsigned char buf[24]; - while (newpos < *new_size) { + while (newpos < new_size) { // Read control data if (FillBuffer(buf, 24, &cstream) != 0) { printf("error while reading control stream\n"); @@ -210,13 +201,13 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, } // Sanity check - if (newpos + ctrl[0] > *new_size) { + if (newpos + ctrl[0] > new_size) { printf("corrupt patch (new file overrun)\n"); return 1; } // Read diff string - if (FillBuffer(*new_data + newpos, ctrl[0], &dstream) != 0) { + if (FillBuffer(new_data->data() + newpos, ctrl[0], &dstream) != 0) { printf("error while reading diff stream\n"); return 1; } @@ -233,13 +224,13 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, oldpos += ctrl[0]; // Sanity check - if (newpos + ctrl[1] > *new_size) { + if (newpos + ctrl[1] > new_size) { printf("corrupt patch (new file overrun)\n"); return 1; } // Read extra string - if (FillBuffer(*new_data + newpos, ctrl[1], &estream) != 0) { + if (FillBuffer(new_data->data() + newpos, ctrl[1], &estream) != 0) { printf("error while reading extra stream\n"); return 1; } diff --git a/applypatch/freecache.cpp b/applypatch/freecache.cpp index 2eb2f55ef..c84f42797 100644 --- a/applypatch/freecache.cpp +++ b/applypatch/freecache.cpp @@ -25,119 +25,90 @@ #include <dirent.h> #include <ctype.h> +#include <memory> +#include <set> +#include <string> + +#include <android-base/parseint.h> +#include <android-base/stringprintf.h> + #include "applypatch.h" -static int EliminateOpenFiles(char** files, int file_count) { - DIR* d; - struct dirent* de; - d = opendir("/proc"); - if (d == NULL) { +static int EliminateOpenFiles(std::set<std::string>* files) { + std::unique_ptr<DIR, decltype(&closedir)> d(opendir("/proc"), closedir); + if (!d) { printf("error opening /proc: %s\n", strerror(errno)); return -1; } - while ((de = readdir(d)) != 0) { - int i; - for (i = 0; de->d_name[i] != '\0' && isdigit(de->d_name[i]); ++i); - if (de->d_name[i]) continue; - - // de->d_name[i] is numeric - - char path[FILENAME_MAX]; - strcpy(path, "/proc/"); - strcat(path, de->d_name); - strcat(path, "/fd/"); + struct dirent* de; + while ((de = readdir(d.get())) != 0) { + unsigned int pid; + if (!android::base::ParseUint(de->d_name, &pid)) { + continue; + } + std::string path = android::base::StringPrintf("/proc/%s/fd/", de->d_name); - DIR* fdd; struct dirent* fdde; - fdd = opendir(path); - if (fdd == NULL) { - printf("error opening %s: %s\n", path, strerror(errno)); + std::unique_ptr<DIR, decltype(&closedir)> fdd(opendir(path.c_str()), closedir); + if (!fdd) { + printf("error opening %s: %s\n", path.c_str(), strerror(errno)); continue; } - while ((fdde = readdir(fdd)) != 0) { - char fd_path[FILENAME_MAX]; + while ((fdde = readdir(fdd.get())) != 0) { + std::string fd_path = path + fdde->d_name; char link[FILENAME_MAX]; - strcpy(fd_path, path); - strcat(fd_path, fdde->d_name); - int count; - count = readlink(fd_path, link, sizeof(link)-1); + int count = readlink(fd_path.c_str(), link, sizeof(link)-1); if (count >= 0) { link[count] = '\0'; - - // This is inefficient, but it should only matter if there are - // lots of files in /cache, and lots of them are open (neither - // of which should be true, especially in recovery). if (strncmp(link, "/cache/", 7) == 0) { - int j; - for (j = 0; j < file_count; ++j) { - if (files[j] && strcmp(files[j], link) == 0) { - printf("%s is open by %s\n", link, de->d_name); - free(files[j]); - files[j] = NULL; - } + if (files->erase(link) > 0) { + printf("%s is open by %s\n", link, de->d_name); } } } } - closedir(fdd); } - closedir(d); - return 0; } -int FindExpendableFiles(char*** names, int* entries) { - DIR* d; - struct dirent* de; - int size = 32; - *entries = 0; - *names = reinterpret_cast<char**>(malloc(size * sizeof(char*))); - - char path[FILENAME_MAX]; - +static std::set<std::string> FindExpendableFiles() { + std::set<std::string> files; // We're allowed to delete unopened regular files in any of these // directories. const char* dirs[2] = {"/cache", "/cache/recovery/otatest"}; for (size_t i = 0; i < sizeof(dirs)/sizeof(dirs[0]); ++i) { - d = opendir(dirs[i]); - if (d == NULL) { + std::unique_ptr<DIR, decltype(&closedir)> d(opendir(dirs[i]), closedir); + if (!d) { printf("error opening %s: %s\n", dirs[i], strerror(errno)); continue; } // Look for regular files in the directory (not in any subdirectories). - while ((de = readdir(d)) != 0) { - strcpy(path, dirs[i]); - strcat(path, "/"); - strcat(path, de->d_name); + struct dirent* de; + while ((de = readdir(d.get())) != 0) { + std::string path = std::string(dirs[i]) + "/" + de->d_name; // We can't delete CACHE_TEMP_SOURCE; if it's there we might have // restarted during installation and could be depending on it to // be there. - if (strcmp(path, CACHE_TEMP_SOURCE) == 0) continue; + if (path == CACHE_TEMP_SOURCE) { + continue; + } struct stat st; - if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) { - if (*entries >= size) { - size *= 2; - *names = reinterpret_cast<char**>(realloc(*names, size * sizeof(char*))); - } - (*names)[(*entries)++] = strdup(path); + if (stat(path.c_str(), &st) == 0 && S_ISREG(st.st_mode)) { + files.insert(path); } } - - closedir(d); } - printf("%d regular files in deletable directories\n", *entries); - - if (EliminateOpenFiles(*names, *entries) < 0) { - return -1; + printf("%zu regular files in deletable directories\n", files.size()); + if (EliminateOpenFiles(&files) < 0) { + return std::set<std::string>(); } - - return 0; + return files; } int MakeFreeSpaceOnCache(size_t bytes_needed) { @@ -147,15 +118,8 @@ int MakeFreeSpaceOnCache(size_t bytes_needed) { if (free_now >= bytes_needed) { return 0; } - - char** names; - int entries; - - if (FindExpendableFiles(&names, &entries) < 0) { - return -1; - } - - if (entries == 0) { + std::set<std::string> files = FindExpendableFiles(); + if (files.empty()) { // nothing we can delete to free up space! printf("no files can be deleted to free space on /cache\n"); return -1; @@ -167,20 +131,13 @@ int MakeFreeSpaceOnCache(size_t bytes_needed) { // // Instead, we'll be dumb. - int i; - for (i = 0; i < entries && free_now < bytes_needed; ++i) { - if (names[i]) { - unlink(names[i]); - free_now = FreeSpaceForFile("/cache"); - printf("deleted %s; now %zu bytes free\n", names[i], free_now); - free(names[i]); + for (const auto& file : files) { + unlink(file.c_str()); + free_now = FreeSpaceForFile("/cache"); + printf("deleted %s; now %zu bytes free\n", file.c_str(), free_now); + if (free_now < bytes_needed) { + break; } } - - for (; i < entries; ++i) { - free(names[i]); - } - free(names); - return (free_now >= bytes_needed) ? 0 : -1; } diff --git a/applypatch/imgpatch.cpp b/applypatch/imgpatch.cpp index 3e72b2cb5..8824038ea 100644 --- a/applypatch/imgpatch.cpp +++ b/applypatch/imgpatch.cpp @@ -21,12 +21,13 @@ #include <sys/cdefs.h> #include <sys/stat.h> #include <errno.h> -#include <malloc.h> #include <unistd.h> #include <string.h> +#include <vector> + #include "zlib.h" -#include "mincrypt/sha.h" +#include "openssl/sha.h" #include "applypatch.h" #include "imgdiff.h" #include "utils.h" @@ -109,7 +110,7 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, printf("failed to read chunk %d raw data\n", i); return -1; } - if (ctx) SHA_update(ctx, patch->data + pos, data_len); + if (ctx) SHA1_Update(ctx, patch->data + pos, data_len); if (sink((unsigned char*)patch->data + pos, data_len, token) != data_len) { printf("failed to write chunk %d raw data\n", i); @@ -129,7 +130,6 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, size_t src_len = Read8(deflate_header+8); size_t patch_offset = Read8(deflate_header+16); size_t expanded_len = Read8(deflate_header+24); - size_t target_len = Read8(deflate_header+32); int level = Read4(deflate_header+40); int method = Read4(deflate_header+44); int windowBits = Read4(deflate_header+48); @@ -150,13 +150,7 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, // must be appended from the bonus_data value. size_t bonus_size = (i == 1 && bonus_data != NULL) ? bonus_data->size : 0; - unsigned char* expanded_source = reinterpret_cast<unsigned char*>(malloc(expanded_len)); - if (expanded_source == NULL) { - printf("failed to allocate %zu bytes for expanded_source\n", - expanded_len); - return -1; - } - + std::vector<unsigned char> expanded_source(expanded_len); z_stream strm; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; @@ -164,7 +158,7 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, strm.avail_in = src_len; strm.next_in = (unsigned char*)(old_data + src_start); strm.avail_out = expanded_len; - strm.next_out = expanded_source; + strm.next_out = expanded_source.data(); int ret; ret = inflateInit2(&strm, -15); @@ -189,18 +183,16 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, inflateEnd(&strm); if (bonus_size) { - memcpy(expanded_source + (expanded_len - bonus_size), + memcpy(expanded_source.data() + (expanded_len - bonus_size), bonus_data->data, bonus_size); } // Next, apply the bsdiff patch (in memory) to the uncompressed // data. - unsigned char* uncompressed_target_data; - ssize_t uncompressed_target_size; - if (ApplyBSDiffPatchMem(expanded_source, expanded_len, + std::vector<unsigned char> uncompressed_target_data; + if (ApplyBSDiffPatchMem(expanded_source.data(), expanded_len, patch, patch_offset, - &uncompressed_target_data, - &uncompressed_target_size) != 0) { + &uncompressed_target_data) != 0) { return -1; } @@ -208,40 +200,36 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, // we're done with the expanded_source data buffer, so we'll // reuse that memory to receive the output of deflate. - unsigned char* temp_data = expanded_source; - ssize_t temp_size = expanded_len; - if (temp_size < 32768) { - // ... unless the buffer is too small, in which case we'll - // allocate a fresh one. - free(temp_data); - temp_data = reinterpret_cast<unsigned char*>(malloc(32768)); - temp_size = 32768; + if (expanded_source.size() < 32768U) { + expanded_source.resize(32768U); } + std::vector<unsigned char>& temp_data = expanded_source; // now the deflate stream strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; - strm.avail_in = uncompressed_target_size; - strm.next_in = uncompressed_target_data; + strm.avail_in = uncompressed_target_data.size(); + strm.next_in = uncompressed_target_data.data(); ret = deflateInit2(&strm, level, method, windowBits, memLevel, strategy); + if (ret != Z_OK) { + printf("failed to init uncompressed data deflation: %d\n", ret); + return -1; + } do { - strm.avail_out = temp_size; - strm.next_out = temp_data; + strm.avail_out = temp_data.size(); + strm.next_out = temp_data.data(); ret = deflate(&strm, Z_FINISH); - ssize_t have = temp_size - strm.avail_out; + ssize_t have = temp_data.size() - strm.avail_out; - if (sink(temp_data, have, token) != have) { + if (sink(temp_data.data(), have, token) != have) { printf("failed to write %ld compressed bytes to output\n", (long)have); return -1; } - if (ctx) SHA_update(ctx, temp_data, have); + if (ctx) SHA1_Update(ctx, temp_data.data(), have); } while (ret != Z_STREAM_END); deflateEnd(&strm); - - free(temp_data); - free(uncompressed_target_data); } else { printf("patch chunk %d is unknown type %d\n", i, type); return -1; diff --git a/applypatch/main.cpp b/applypatch/main.cpp index 966d8b91f..7606d5d3c 100644 --- a/applypatch/main.cpp +++ b/applypatch/main.cpp @@ -19,9 +19,12 @@ #include <string.h> #include <unistd.h> +#include <memory> +#include <vector> + #include "applypatch.h" #include "edify/expr.h" -#include "mincrypt/sha.h" +#include "openssl/sha.h" static int CheckMode(int argc, char** argv) { if (argc < 3) { @@ -47,16 +50,11 @@ static int SpaceMode(int argc, char** argv) { // "<sha1>:<filename>" into the new parallel arrays *sha1s and // *patches (loading file contents into the patches). Returns true on // success. -static bool ParsePatchArgs(int argc, char** argv, char*** sha1s, - Value*** patches, int* num_patches) { - *num_patches = argc; - *sha1s = reinterpret_cast<char**>(malloc(*num_patches * sizeof(char*))); - *patches = reinterpret_cast<Value**>(malloc(*num_patches * sizeof(Value*))); - memset(*patches, 0, *num_patches * sizeof(Value*)); - - uint8_t digest[SHA_DIGEST_SIZE]; +static bool ParsePatchArgs(int argc, char** argv, std::vector<char*>* sha1s, + std::vector<std::unique_ptr<Value, decltype(&FreeValue)>>* patches) { + uint8_t digest[SHA_DIGEST_LENGTH]; - for (int i = 0; i < *num_patches; ++i) { + for (int i = 0; i < argc; ++i) { char* colon = strchr(argv[i], ':'); if (colon != NULL) { *colon = '\0'; @@ -68,34 +66,22 @@ static bool ParsePatchArgs(int argc, char** argv, char*** sha1s, return false; } - (*sha1s)[i] = argv[i]; + sha1s->push_back(argv[i]); if (colon == NULL) { - (*patches)[i] = NULL; + patches->emplace_back(nullptr, FreeValue); } else { FileContents fc; if (LoadFileContents(colon, &fc) != 0) { - goto abort; + return false; } - (*patches)[i] = reinterpret_cast<Value*>(malloc(sizeof(Value))); - (*patches)[i]->type = VAL_BLOB; - (*patches)[i]->size = fc.size; - (*patches)[i]->data = reinterpret_cast<char*>(fc.data); + std::unique_ptr<Value, decltype(&FreeValue)> value(new Value, FreeValue); + value->type = VAL_BLOB; + value->size = fc.size; + value->data = reinterpret_cast<char*>(fc.data); + patches->push_back(std::move(value)); } } - return true; - - abort: - for (int i = 0; i < *num_patches; ++i) { - Value* p = (*patches)[i]; - if (p != NULL) { - free(p->data); - free(p); - } - } - free(*sha1s); - free(*patches); - return false; } static int FlashMode(const char* src_filename, const char* tgt_filename, @@ -104,17 +90,17 @@ static int FlashMode(const char* src_filename, const char* tgt_filename, } static int PatchMode(int argc, char** argv) { - Value* bonus = NULL; + std::unique_ptr<Value, decltype(&FreeValue)> bonus(nullptr, FreeValue); if (argc >= 3 && strcmp(argv[1], "-b") == 0) { FileContents fc; if (LoadFileContents(argv[2], &fc) != 0) { printf("failed to load bonus file %s\n", argv[2]); return 1; } - bonus = reinterpret_cast<Value*>(malloc(sizeof(Value))); + bonus.reset(new Value); bonus->type = VAL_BLOB; bonus->size = fc.size; - bonus->data = (char*)fc.data; + bonus->data = reinterpret_cast<char*>(fc.data); argc -= 2; argv += 2; } @@ -140,33 +126,20 @@ static int PatchMode(int argc, char** argv) { } - char** sha1s; - Value** patches; - int num_patches; - if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &patches, &num_patches)) { + std::vector<char*> sha1s; + std::vector<std::unique_ptr<Value, decltype(&FreeValue)>> patches; + if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &patches)) { printf("failed to parse patch args\n"); return 1; } - int result = applypatch(argv[1], argv[2], argv[3], target_size, - num_patches, sha1s, patches, bonus); - - int i; - for (i = 0; i < num_patches; ++i) { - Value* p = patches[i]; - if (p != NULL) { - free(p->data); - free(p); - } - } - if (bonus) { - free(bonus->data); - free(bonus); + std::vector<Value*> patch_ptrs; + for (const auto& p : patches) { + patch_ptrs.push_back(p.get()); } - free(sha1s); - free(patches); - - return result; + return applypatch(argv[1], argv[2], argv[3], target_size, + patch_ptrs.size(), sha1s.data(), + patch_ptrs.data(), bonus.get()); } // This program applies binary patches to files in a way that is safe diff --git a/print_sha1.h b/print_sha1.h index 9e37c5fe3..fa3d7e009 100644 --- a/print_sha1.h +++ b/print_sha1.h @@ -20,9 +20,9 @@ #include <stdint.h> #include <string> -#include "mincrypt/sha.h" +#include "openssl/sha.h" -static std::string print_sha1(const uint8_t sha1[SHA_DIGEST_SIZE], size_t len) { +static std::string print_sha1(const uint8_t sha1[SHA_DIGEST_LENGTH], size_t len) { const char* hex = "0123456789abcdef"; std::string result = ""; for (size_t i = 0; i < len; ++i) { @@ -32,11 +32,11 @@ static std::string print_sha1(const uint8_t sha1[SHA_DIGEST_SIZE], size_t len) { return result; } -static std::string print_sha1(const uint8_t sha1[SHA_DIGEST_SIZE]) { - return print_sha1(sha1, SHA_DIGEST_SIZE); +static std::string print_sha1(const uint8_t sha1[SHA_DIGEST_LENGTH]) { + return print_sha1(sha1, SHA_DIGEST_LENGTH); } -static std::string short_sha1(const uint8_t sha1[SHA_DIGEST_SIZE]) { +static std::string short_sha1(const uint8_t sha1[SHA_DIGEST_LENGTH]) { return print_sha1(sha1, 4); } diff --git a/tests/Android.mk b/tests/Android.mk index 4ce00b457..3f3c433eb 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -16,11 +16,40 @@ LOCAL_PATH := $(call my-dir) +# Unit tests include $(CLEAR_VARS) LOCAL_CLANG := true +LOCAL_MODULE := recovery_unit_test LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_STATIC_LIBRARIES := libverifier -LOCAL_SRC_FILES := asn1_decoder_test.cpp -LOCAL_MODULE := asn1_decoder_test -LOCAL_C_INCLUDES := $(LOCAL_PATH)/.. +LOCAL_SRC_FILES := unit/asn1_decoder_test.cpp +LOCAL_C_INCLUDES := bootable/recovery +include $(BUILD_NATIVE_TEST) + +# Component tests +include $(CLEAR_VARS) +LOCAL_CLANG := true +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +LOCAL_MODULE := recovery_component_test +LOCAL_C_INCLUDES := bootable/recovery +LOCAL_SRC_FILES := component/verifier_test.cpp +LOCAL_FORCE_STATIC_EXECUTABLE := true +LOCAL_STATIC_LIBRARIES := \ + libbase \ + libverifier \ + libmincrypt \ + libminui \ + libminzip \ + libcutils \ + libc + +testdata_out_path := $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE) +testdata_files := $(call find-subdir-files, testdata/*) + +GEN := $(addprefix $(testdata_out_path)/, $(testdata_files)) +$(GEN): PRIVATE_PATH := $(LOCAL_PATH) +$(GEN): PRIVATE_CUSTOM_TOOL = cp $< $@ +$(GEN): $(testdata_out_path)/% : $(LOCAL_PATH)/% + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) include $(BUILD_NATIVE_TEST) diff --git a/verifier_test.cpp b/tests/component/verifier_test.cpp index 2367e0052..7f7b1b448 100644 --- a/verifier_test.cpp +++ b/tests/component/verifier_test.cpp @@ -1,13 +1,13 @@ /* * Copyright (C) 2009 The Android Open Source Project * - * Licensed under the Apache License, Version 2.0 (the "License"); + * Licensed under the Apache License, version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software + * Unless required by applicable law or agree to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and @@ -16,22 +16,33 @@ #include <errno.h> #include <fcntl.h> -#include <stdarg.h> +#include <gtest/gtest.h> #include <stdio.h> #include <stdlib.h> -#include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <memory> +#include <string> #include <vector> +#include <android-base/stringprintf.h> + #include "common.h" -#include "verifier.h" -#include "ui.h" #include "mincrypt/sha.h" #include "mincrypt/sha256.h" #include "minzip/SysUtil.h" +#include "ui.h" +#include "verifier.h" + +#if defined(__LP64__) +#define NATIVE_TEST_PATH "/nativetest64" +#else +#define NATIVE_TEST_PATH "/nativetest" +#endif + +static const char* DATA_PATH = getenv("ANDROID_DATA"); +static const char* TESTDATA_PATH = "/recovery_component_test/testdata/"; // This is build/target/product/security/testkey.x509.pem after being // dumped out by dumpkey.jar. @@ -123,9 +134,7 @@ ECPublicKey test_ec_key = RecoveryUI* ui = NULL; -// verifier expects to find a UI object; we provide one that does -// nothing but print. -class FakeUI : public RecoveryUI { +class MockUI : public RecoveryUI { void Init() { } void SetStage(int, int) { } void SetLocale(const char*) { } @@ -166,79 +175,93 @@ ui_print(const char* format, ...) { va_end(ap); } -int main(int argc, char** argv) { - if (argc < 2) { - fprintf(stderr, "Usage: %s [-sha256] [-ec | -f4 | -file <keys>] <package>\n", argv[0]); - return 2; - } - +class VerifierTest : public testing::TestWithParam<std::vector<std::string>> { + public: + MemMapping memmap; std::vector<Certificate> certs; - int argn = 1; - while (argn < argc) { - if (strcmp(argv[argn], "-sha256") == 0) { - if (certs.empty()) { - fprintf(stderr, "May only specify -sha256 after key type\n"); - return 2; + + virtual void SetUp() { + std::vector<std::string> args = GetParam(); + std::string package = android::base::StringPrintf("%s%s%s%s", DATA_PATH, NATIVE_TEST_PATH, + TESTDATA_PATH, args[0].c_str()); + for (auto it = ++(args.cbegin()); it != args.cend(); ++it) { + if (it->substr(it->length() - 3, it->length()) == "256") { + if (certs.empty()) { + FAIL() << "May only specify -sha256 after key type\n"; + } + certs.back().hash_len = SHA256_DIGEST_SIZE; + } else if (*it == "ec") { + certs.emplace_back(SHA_DIGEST_SIZE, Certificate::EC, + nullptr, std::unique_ptr<ECPublicKey>(new ECPublicKey(test_ec_key))); + } else if (*it == "e3") { + certs.emplace_back(SHA_DIGEST_SIZE, Certificate::RSA, + std::unique_ptr<RSAPublicKey>(new RSAPublicKey(test_key)), nullptr); + } else if (*it == "f4") { + certs.emplace_back(SHA_DIGEST_SIZE, Certificate::RSA, + std::unique_ptr<RSAPublicKey>(new RSAPublicKey(test_f4_key)), nullptr); } - ++argn; - certs.back().hash_len = SHA256_DIGEST_SIZE; - } else if (strcmp(argv[argn], "-ec") == 0) { - ++argn; - certs.emplace_back(SHA_DIGEST_SIZE, Certificate::EC, - nullptr, std::unique_ptr<ECPublicKey>(new ECPublicKey(test_ec_key))); - } else if (strcmp(argv[argn], "-e3") == 0) { - ++argn; + } + if (certs.empty()) { certs.emplace_back(SHA_DIGEST_SIZE, Certificate::RSA, std::unique_ptr<RSAPublicKey>(new RSAPublicKey(test_key)), nullptr); - } else if (strcmp(argv[argn], "-f4") == 0) { - ++argn; - certs.emplace_back(SHA_DIGEST_SIZE, Certificate::RSA, - std::unique_ptr<RSAPublicKey>(new RSAPublicKey(test_f4_key)), nullptr); - } else if (strcmp(argv[argn], "-file") == 0) { - if (!certs.empty()) { - fprintf(stderr, "Cannot specify -file with other certs specified\n"); - return 2; - } - ++argn; - if (!load_keys(argv[argn], certs)) { - fprintf(stderr, "Cannot load keys from %s\n", argv[argn]); - } - ++argn; - } else if (argv[argn][0] == '-') { - fprintf(stderr, "Unknown argument %s\n", argv[argn]); - return 2; - } else { - break; + } + if (sysMapFile(package.c_str(), &memmap) != 0) { + FAIL() << "Failed to mmap " << package << ": " << strerror(errno) << "\n"; } } - if (argn == argc) { - fprintf(stderr, "Must specify package to verify\n"); - return 2; + static void SetUpTestCase() { + ui = new MockUI(); } +}; - if (certs.empty()) { - certs.emplace_back(SHA_DIGEST_SIZE, Certificate::RSA, - std::unique_ptr<RSAPublicKey>(new RSAPublicKey(test_key)), nullptr); - } +class VerifierSuccessTest : public VerifierTest { +}; - ui = new FakeUI(); +class VerifierFailureTest : public VerifierTest { +}; - MemMapping map; - if (sysMapFile(argv[argn], &map) != 0) { - fprintf(stderr, "failed to mmap %s: %s\n", argv[argn], strerror(errno)); - return 4; - } +TEST_P(VerifierSuccessTest, VerifySucceed) { + ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs), VERIFY_SUCCESS); +} - int result = verify_file(map.addr, map.length, certs); - if (result == VERIFY_SUCCESS) { - printf("VERIFIED\n"); - return 0; - } else if (result == VERIFY_FAILURE) { - printf("NOT VERIFIED\n"); - return 1; - } else { - printf("bad return value\n"); - return 3; - } +TEST_P(VerifierFailureTest, VerifyFailure) { + ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs), VERIFY_FAILURE); } + +INSTANTIATE_TEST_CASE_P(SingleKeySuccess, VerifierSuccessTest, + ::testing::Values( + std::vector<std::string>({"otasigned.zip", "e3"}), + std::vector<std::string>({"otasigned_f4.zip", "f4"}), + std::vector<std::string>({"otasigned_sha256.zip", "e3", "sha256"}), + std::vector<std::string>({"otasigned_f4_sha256.zip", "f4", "sha256"}), + std::vector<std::string>({"otasigned_ecdsa_sha256.zip", "ec", "sha256"}))); + +INSTANTIATE_TEST_CASE_P(MultiKeySuccess, VerifierSuccessTest, + ::testing::Values( + std::vector<std::string>({"otasigned.zip", "f4", "e3"}), + std::vector<std::string>({"otasigned_f4.zip", "ec", "f4"}), + std::vector<std::string>({"otasigned_sha256.zip", "ec", "e3", "e3", "sha256"}), + std::vector<std::string>({"otasigned_f4_sha256.zip", "ec", "sha256", "e3", "f4", "sha256"}), + std::vector<std::string>({"otasigned_ecdsa_sha256.zip", "f4", "sha256", "e3", "ec", "sha256"}))); + +INSTANTIATE_TEST_CASE_P(WrongKey, VerifierFailureTest, + ::testing::Values( + std::vector<std::string>({"otasigned.zip", "f4"}), + std::vector<std::string>({"otasigned_f4.zip", "e3"}), + std::vector<std::string>({"otasigned_ecdsa_sha256.zip", "e3", "sha256"}))); + +INSTANTIATE_TEST_CASE_P(WrongHash, VerifierFailureTest, + ::testing::Values( + std::vector<std::string>({"otasigned.zip", "e3", "sha256"}), + std::vector<std::string>({"otasigned_f4.zip", "f4", "sha256"}), + std::vector<std::string>({"otasigned_sha256.zip"}), + std::vector<std::string>({"otasigned_f4_sha256.zip", "f4"}), + std::vector<std::string>({"otasigned_ecdsa_sha256.zip"}))); + +INSTANTIATE_TEST_CASE_P(BadPackage, VerifierFailureTest, + ::testing::Values( + std::vector<std::string>({"random.zip"}), + std::vector<std::string>({"fake-eocd.zip"}), + std::vector<std::string>({"alter-metadata.zip"}), + std::vector<std::string>({"alter-footer.zip"}))); diff --git a/testdata/alter-footer.zip b/tests/testdata/alter-footer.zip Binary files differindex f497ec000..f497ec000 100644 --- a/testdata/alter-footer.zip +++ b/tests/testdata/alter-footer.zip diff --git a/testdata/alter-metadata.zip b/tests/testdata/alter-metadata.zip Binary files differindex 1c71fbc49..1c71fbc49 100644 --- a/testdata/alter-metadata.zip +++ b/tests/testdata/alter-metadata.zip diff --git a/testdata/fake-eocd.zip b/tests/testdata/fake-eocd.zip Binary files differindex 15dc0a946..15dc0a946 100644 --- a/testdata/fake-eocd.zip +++ b/tests/testdata/fake-eocd.zip diff --git a/testdata/jarsigned.zip b/tests/testdata/jarsigned.zip Binary files differindex 8b1ef8bdd..8b1ef8bdd 100644 --- a/testdata/jarsigned.zip +++ b/tests/testdata/jarsigned.zip diff --git a/testdata/otasigned.zip b/tests/testdata/otasigned.zip Binary files differindex a6bc53e41..a6bc53e41 100644 --- a/testdata/otasigned.zip +++ b/tests/testdata/otasigned.zip diff --git a/testdata/otasigned_ecdsa_sha256.zip b/tests/testdata/otasigned_ecdsa_sha256.zip Binary files differindex 999fcdd0f..999fcdd0f 100644 --- a/testdata/otasigned_ecdsa_sha256.zip +++ b/tests/testdata/otasigned_ecdsa_sha256.zip diff --git a/testdata/otasigned_f4.zip b/tests/testdata/otasigned_f4.zip Binary files differindex dd1e4dd40..dd1e4dd40 100644 --- a/testdata/otasigned_f4.zip +++ b/tests/testdata/otasigned_f4.zip diff --git a/testdata/otasigned_f4_sha256.zip b/tests/testdata/otasigned_f4_sha256.zip Binary files differindex 3af408c40..3af408c40 100644 --- a/testdata/otasigned_f4_sha256.zip +++ b/tests/testdata/otasigned_f4_sha256.zip diff --git a/testdata/otasigned_sha256.zip b/tests/testdata/otasigned_sha256.zip Binary files differindex 0ed4409b3..0ed4409b3 100644 --- a/testdata/otasigned_sha256.zip +++ b/tests/testdata/otasigned_sha256.zip diff --git a/testdata/random.zip b/tests/testdata/random.zip Binary files differindex 18c0b3b9f..18c0b3b9f 100644 --- a/testdata/random.zip +++ b/tests/testdata/random.zip diff --git a/testdata/test_f4.pk8 b/tests/testdata/test_f4.pk8 Binary files differindex 3052613c5..3052613c5 100644 --- a/testdata/test_f4.pk8 +++ b/tests/testdata/test_f4.pk8 diff --git a/testdata/test_f4.x509.pem b/tests/testdata/test_f4.x509.pem index 814abcf99..814abcf99 100644 --- a/testdata/test_f4.x509.pem +++ b/tests/testdata/test_f4.x509.pem diff --git a/testdata/test_f4_sha256.x509.pem b/tests/testdata/test_f4_sha256.x509.pem index 9d5376b45..9d5376b45 100644 --- a/testdata/test_f4_sha256.x509.pem +++ b/tests/testdata/test_f4_sha256.x509.pem diff --git a/testdata/testkey.pk8 b/tests/testdata/testkey.pk8 Binary files differindex 586c1bd5c..586c1bd5c 100644 --- a/testdata/testkey.pk8 +++ b/tests/testdata/testkey.pk8 diff --git a/testdata/testkey.x509.pem b/tests/testdata/testkey.x509.pem index e242d83e2..e242d83e2 100644 --- a/testdata/testkey.x509.pem +++ b/tests/testdata/testkey.x509.pem diff --git a/testdata/testkey_ecdsa.pk8 b/tests/testdata/testkey_ecdsa.pk8 Binary files differindex 9a521c8cf..9a521c8cf 100644 --- a/testdata/testkey_ecdsa.pk8 +++ b/tests/testdata/testkey_ecdsa.pk8 diff --git a/testdata/testkey_ecdsa.x509.pem b/tests/testdata/testkey_ecdsa.x509.pem index b12283645..b12283645 100644 --- a/testdata/testkey_ecdsa.x509.pem +++ b/tests/testdata/testkey_ecdsa.x509.pem diff --git a/testdata/testkey_sha256.x509.pem b/tests/testdata/testkey_sha256.x509.pem index 002ce8968..002ce8968 100644 --- a/testdata/testkey_sha256.x509.pem +++ b/tests/testdata/testkey_sha256.x509.pem diff --git a/testdata/unsigned.zip b/tests/testdata/unsigned.zip Binary files differindex 24e3eadac..24e3eadac 100644 --- a/testdata/unsigned.zip +++ b/tests/testdata/unsigned.zip diff --git a/tests/asn1_decoder_test.cpp b/tests/unit/asn1_decoder_test.cpp index af96d87d2..af96d87d2 100644 --- a/tests/asn1_decoder_test.cpp +++ b/tests/unit/asn1_decoder_test.cpp diff --git a/updater/Android.mk b/updater/Android.mk index d74dffc0c..d7aa613e9 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -46,7 +46,7 @@ endif LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UPDATER_LIBS) $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS) LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libedify libmtdutils libminzip libz -LOCAL_STATIC_LIBRARIES += libmincrypt libbz +LOCAL_STATIC_LIBRARIES += libbz LOCAL_STATIC_LIBRARIES += libcutils liblog libc LOCAL_STATIC_LIBRARIES += libselinux tune2fs_static_libraries := \ diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index c898ac6f6..e9c8ddbc0 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -43,7 +43,7 @@ #include "applypatch/applypatch.h" #include "edify/expr.h" #include "install.h" -#include "mincrypt/sha.h" +#include "openssl/sha.h" #include "minzip/Hash.h" #include "otafault/ota_io.h" #include "print_sha1.h" @@ -408,10 +408,10 @@ static int LoadSrcTgtVersion1(CommandParameters& params, RangeSet& tgt, size_t& static int VerifyBlocks(const std::string& expected, const std::vector<uint8_t>& buffer, const size_t blocks, bool printerror) { - uint8_t digest[SHA_DIGEST_SIZE]; + uint8_t digest[SHA_DIGEST_LENGTH]; const uint8_t* data = buffer.data(); - SHA_hash(data, blocks * BLOCKSIZE, digest); + SHA1(data, blocks * BLOCKSIZE, digest); std::string hexdigest = print_sha1(digest); @@ -663,10 +663,8 @@ static int CreateStash(State* state, int maxblocks, const char* blockdev, std::s // Stash directory should be different for each partition to avoid conflicts // when updating multiple partitions at the same time, so we use the hash of // the block device name as the base directory - SHA_CTX ctx; - SHA_init(&ctx); - SHA_update(&ctx, blockdev, strlen(blockdev)); - const uint8_t* digest = SHA_final(&ctx); + uint8_t digest[SHA_DIGEST_LENGTH]; + SHA1(reinterpret_cast<const uint8_t*>(blockdev), strlen(blockdev), digest); base = print_sha1(digest); std::string dirname = GetStashFileName(base, "", ""); @@ -1628,7 +1626,7 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) parse_range(ranges->data, rs); SHA_CTX ctx; - SHA_init(&ctx); + SHA1_Init(&ctx); std::vector<uint8_t> buffer(BLOCKSIZE); for (size_t i = 0; i < rs.count; ++i) { @@ -1644,10 +1642,11 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) return StringValue(strdup("")); } - SHA_update(&ctx, buffer.data(), BLOCKSIZE); + SHA1_Update(&ctx, buffer.data(), BLOCKSIZE); } } - const uint8_t* digest = SHA_final(&ctx); + uint8_t digest[SHA_DIGEST_LENGTH]; + SHA1_Final(digest, &ctx); return StringValue(strdup(print_sha1(digest).c_str())); } diff --git a/updater/install.cpp b/updater/install.cpp index be9735595..a2efc0b97 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -34,6 +34,9 @@ #include <linux/xattr.h> #include <inttypes.h> +#include <memory> +#include <vector> + #include <android-base/parseint.h> #include <android-base/strings.h> #include <android-base/stringprintf.h> @@ -44,7 +47,7 @@ #include "cutils/misc.h" #include "cutils/properties.h" #include "edify/expr.h" -#include "mincrypt/sha.h" +#include "openssl/sha.h" #include "minzip/DirUtil.h" #include "mtdutils/mounts.h" #include "mtdutils/mtdutils.h" @@ -92,10 +95,10 @@ void uiPrintf(State* state, const char* format, ...) { // Take a sha-1 digest and return it as a newly-allocated hex string. char* PrintSha1(const uint8_t* digest) { - char* buffer = reinterpret_cast<char*>(malloc(SHA_DIGEST_SIZE*2 + 1)); + char* buffer = reinterpret_cast<char*>(malloc(SHA_DIGEST_LENGTH*2 + 1)); const char* alphabet = "0123456789abcdef"; size_t i; - for (i = 0; i < SHA_DIGEST_SIZE; ++i) { + for (i = 0; i < SHA_DIGEST_LENGTH; ++i) { buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf]; buffer[i*2+1] = alphabet[digest[i] & 0xf]; } @@ -440,8 +443,7 @@ Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) { for (int i = 0; i < argc; ++i) { paths[i] = Evaluate(state, argv[i]); if (paths[i] == NULL) { - int j; - for (j = 0; j < i; ++i) { + for (int j = 0; j < i; ++j) { free(paths[j]); } free(paths); @@ -582,13 +584,13 @@ Value* PackageExtractFileFn(const char* name, State* state, // as the result. char* zip_path; + if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL; + Value* v = reinterpret_cast<Value*>(malloc(sizeof(Value))); v->type = VAL_BLOB; v->size = -1; v->data = NULL; - if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL; - ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip; const ZipEntry* entry = mzFindZipEntry(za, zip_path); if (entry == NULL) { @@ -1194,44 +1196,40 @@ Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) { } int patchcount = (argc-4) / 2; - Value** patches = ReadValueVarArgs(state, argc-4, argv+4); + std::unique_ptr<Value*, decltype(&free)> arg_values(ReadValueVarArgs(state, argc-4, argv+4), + free); + if (!arg_values) { + return nullptr; + } + std::vector<std::unique_ptr<Value, decltype(&FreeValue)>> patch_shas; + std::vector<std::unique_ptr<Value, decltype(&FreeValue)>> patches; + // Protect values by unique_ptrs first to get rid of memory leak. + for (int i = 0; i < patchcount * 2; i += 2) { + patch_shas.emplace_back(arg_values.get()[i], FreeValue); + patches.emplace_back(arg_values.get()[i+1], FreeValue); + } - int i; - for (i = 0; i < patchcount; ++i) { - if (patches[i*2]->type != VAL_STRING) { + for (int i = 0; i < patchcount; ++i) { + if (patch_shas[i]->type != VAL_STRING) { ErrorAbort(state, "%s(): sha-1 #%d is not string", name, i); - break; + return nullptr; } - if (patches[i*2+1]->type != VAL_BLOB) { + if (patches[i]->type != VAL_BLOB) { ErrorAbort(state, "%s(): patch #%d is not blob", name, i); - break; + return nullptr; } } - if (i != patchcount) { - for (i = 0; i < patchcount*2; ++i) { - FreeValue(patches[i]); - } - free(patches); - return NULL; - } - char** patch_sha_str = reinterpret_cast<char**>(malloc(patchcount * sizeof(char*))); - for (i = 0; i < patchcount; ++i) { - patch_sha_str[i] = patches[i*2]->data; - patches[i*2]->data = NULL; - FreeValue(patches[i*2]); - patches[i] = patches[i*2+1]; + std::vector<char*> patch_sha_str; + std::vector<Value*> patch_ptrs; + for (int i = 0; i < patchcount; ++i) { + patch_sha_str.push_back(patch_shas[i]->data); + patch_ptrs.push_back(patches[i].get()); } int result = applypatch(source_filename, target_filename, target_sha1, target_size, - patchcount, patch_sha_str, patches, NULL); - - for (i = 0; i < patchcount; ++i) { - FreeValue(patches[i]); - } - free(patch_sha_str); - free(patches); + patchcount, patch_sha_str.data(), patch_ptrs.data(), NULL); return StringValue(strdup(result == 0 ? "t" : "")); } @@ -1350,24 +1348,27 @@ Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) { return ErrorAbort(state, "%s() expects at least 1 arg", name); } - Value** args = ReadValueVarArgs(state, argc, argv); - if (args == NULL) { - return NULL; + std::unique_ptr<Value*, decltype(&free)> arg_values(ReadValueVarArgs(state, argc, argv), free); + if (arg_values == nullptr) { + return nullptr; + } + std::vector<std::unique_ptr<Value, decltype(&FreeValue)>> args; + for (int i = 0; i < argc; ++i) { + args.emplace_back(arg_values.get()[i], FreeValue); } if (args[0]->size < 0) { return StringValue(strdup("")); } - uint8_t digest[SHA_DIGEST_SIZE]; - SHA_hash(args[0]->data, args[0]->size, digest); - FreeValue(args[0]); + uint8_t digest[SHA_DIGEST_LENGTH]; + SHA1(reinterpret_cast<uint8_t*>(args[0]->data), args[0]->size, digest); if (argc == 1) { return StringValue(PrintSha1(digest)); } int i; - uint8_t* arg_digest = reinterpret_cast<uint8_t*>(malloc(SHA_DIGEST_SIZE)); + uint8_t arg_digest[SHA_DIGEST_LENGTH]; for (i = 1; i < argc; ++i) { if (args[i]->type != VAL_STRING) { printf("%s(): arg %d is not a string; skipping", @@ -1376,22 +1377,16 @@ Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) { // Warn about bad args and skip them. printf("%s(): error parsing \"%s\" as sha-1; skipping", name, args[i]->data); - } else if (memcmp(digest, arg_digest, SHA_DIGEST_SIZE) == 0) { + } else if (memcmp(digest, arg_digest, SHA_DIGEST_LENGTH) == 0) { break; } - FreeValue(args[i]); } if (i >= argc) { // Didn't match any of the hex strings; return false. return StringValue(strdup("")); } - // Found a match; free all the remaining arguments and return the - // matched one. - int j; - for (j = i+1; j < argc; ++j) { - FreeValue(args[j]); - } - return args[i]; + // Found a match. + return args[i].release(); } // Read a local file and return its contents (the Value* returned diff --git a/verifier_test.sh b/verifier_test.sh deleted file mode 100755 index 4761cef4a..000000000 --- a/verifier_test.sh +++ /dev/null @@ -1,121 +0,0 @@ -#!/bin/bash -# -# A test suite for recovery's package signature verifier. Run in a -# client where you have done envsetup, lunch, etc. -# -# TODO: find some way to get this run regularly along with the rest of -# the tests. - -EMULATOR_PORT=5580 -DATA_DIR=$ANDROID_BUILD_TOP/bootable/recovery/testdata - -WORK_DIR=/data/local/tmp - -# set to 0 to use a device instead -USE_EMULATOR=0 - -# ------------------------ - -if [ "$USE_EMULATOR" == 1 ]; then - emulator -wipe-data -noaudio -no-window -port $EMULATOR_PORT & - pid_emulator=$! - ADB="adb -s emulator-$EMULATOR_PORT " -else - ADB="adb -d " -fi - -echo "waiting to connect to device" -$ADB wait-for-device - -# run a command on the device; exit with the exit status of the device -# command. -run_command() { - $ADB shell "$@" \; echo \$? | awk '{if (b) {print a}; a=$0; b=1} END {exit a}' -} - -testname() { - echo - echo "::: testing $1 :::" - testname="$1" -} - -fail() { - echo - echo FAIL: $testname - echo - [ "$open_pid" == "" ] || kill $open_pid - [ "$pid_emulator" == "" ] || kill $pid_emulator - exit 1 -} - - -cleanup() { - # not necessary if we're about to kill the emulator, but nice for - # running on real devices or already-running emulators. - run_command rm $WORK_DIR/verifier_test - run_command rm $WORK_DIR/package.zip - - [ "$pid_emulator" == "" ] || kill $pid_emulator -} - -$ADB push $ANDROID_PRODUCT_OUT/system/bin/verifier_test \ - $WORK_DIR/verifier_test - -expect_succeed() { - testname "$1 (should succeed)" - $ADB push $DATA_DIR/$1 $WORK_DIR/package.zip - shift - run_command $WORK_DIR/verifier_test "$@" $WORK_DIR/package.zip || fail -} - -expect_fail() { - testname "$1 (should fail)" - $ADB push $DATA_DIR/$1 $WORK_DIR/package.zip - shift - run_command $WORK_DIR/verifier_test "$@" $WORK_DIR/package.zip && fail -} - -# not signed at all -expect_fail unsigned.zip -# signed in the pre-donut way -expect_fail jarsigned.zip - -# success cases -expect_succeed otasigned.zip -e3 -expect_succeed otasigned_f4.zip -f4 -expect_succeed otasigned_sha256.zip -e3 -sha256 -expect_succeed otasigned_f4_sha256.zip -f4 -sha256 -expect_succeed otasigned_ecdsa_sha256.zip -ec -sha256 - -# success with multiple keys -expect_succeed otasigned.zip -f4 -e3 -expect_succeed otasigned_f4.zip -ec -f4 -expect_succeed otasigned_sha256.zip -ec -e3 -e3 -sha256 -expect_succeed otasigned_f4_sha256.zip -ec -sha256 -e3 -f4 -sha256 -expect_succeed otasigned_ecdsa_sha256.zip -f4 -sha256 -e3 -ec -sha256 - -# verified against different key -expect_fail otasigned.zip -f4 -expect_fail otasigned_f4.zip -e3 -expect_fail otasigned_ecdsa_sha256.zip -e3 -sha256 - -# verified against right key but wrong hash algorithm -expect_fail otasigned.zip -e3 -sha256 -expect_fail otasigned_f4.zip -f4 -sha256 -expect_fail otasigned_sha256.zip -expect_fail otasigned_f4_sha256.zip -f4 -expect_fail otasigned_ecdsa_sha256.zip - -# various other cases -expect_fail random.zip -expect_fail fake-eocd.zip -expect_fail alter-metadata.zip -expect_fail alter-footer.zip - -# --------------- cleanup ---------------------- - -cleanup - -echo -echo PASS -echo |