/* Select and initialize either the software or hardware * implementation. If "multi-threaded" behaviour is required, then * callers must set sw_required to 1. This is because SHA1 state * internal to the hardware cannot be extracted, so it is not possible * to suspend and resume a hardware based SHA operation. * * If the caller has no preference as to implementation, then hardware * is preferred based on availability. Hardware is considered to be * in use between init() and finished() calls. */ void DCRYPTO_SHA1_init(SHA_CTX *ctx, uint32_t sw_required) { if (!sw_required && dcrypto_grab_sha_hw()) dcrypto_sha1_init(ctx); else SHA_init(ctx); }
/* Convenience function */ const uint8_t* SHA(const void* data, int len, uint8_t* digest) { SHA_CTX ctx; SHA_init(&ctx); SHA_update(&ctx, data, len); memcpy(digest, SHA_final(&ctx), SHA_DIGEST_SIZE); return digest; }
int main(int argc, char *argv[]) { SHA_CTX ctx; unsigned char buf[1024]; unsigned char md[20]; FILE *fp; int i, nread; fp = fopen(argv[1], "r"); if (fp == NULL) { fprintf(stderr, "Open failed\n"); exit(-1); } SHA_init(&ctx); while (!feof(fp)) { nread = fread(buf, 1, sizeof(buf), fp); SHA_update(&ctx, buf, nread); } SHA_final(md, &ctx); for (i = 0; i < 20; i++) printf("%02x", md[i]); printf("\n"); return 0; }
// get hex sha char * shaFile(const char * filename){ #define BUF_SHA 4096 char buf[BUF_SHA]; SHA_CTX sha_ctx; SHA_init(&sha_ctx); FILE * file = fopen(filename, "rb"); if(file == NULL){ fprintf(stderr, "can not open file %s for sha\n", filename); return NULL; } int read = 0; while( (read = fread(buf, 1, BUF_SHA, file) ) > 0){ SHA_update(&sha_ctx, buf, read); } if(fclose(file)) return NULL; const char * sha_final = (char *)SHA_final(&sha_ctx); if(sha_final == NULL) return NULL; char * hex = (char *)malloc(sizeof(char ) * (2 * SHA_DIGEST_SIZE + 1 )); if(!hex) return NULL; if(!hexSha1(sha_final, hex)) return hex; free(hex); hex=NULL; return NULL; }
void generate_id_sha1(boot_img_hdr_v2 *hdr, void *kernel_data, void *ramdisk_data, void *second_data, void *dt_data, void *recovery_dtbo_data, void *dtb_data) { SHA_CTX ctx; const uint8_t *sha; SHA_init(&ctx); SHA_update(&ctx, kernel_data, hdr->kernel_size); SHA_update(&ctx, &hdr->kernel_size, sizeof(hdr->kernel_size)); SHA_update(&ctx, ramdisk_data, hdr->ramdisk_size); SHA_update(&ctx, &hdr->ramdisk_size, sizeof(hdr->ramdisk_size)); SHA_update(&ctx, second_data, hdr->second_size); SHA_update(&ctx, &hdr->second_size, sizeof(hdr->second_size)); if(dt_data) { SHA_update(&ctx, dt_data, hdr->dt_size); SHA_update(&ctx, &hdr->dt_size, sizeof(hdr->dt_size)); } else if(hdr->header_version > 0) { SHA_update(&ctx, recovery_dtbo_data, hdr->recovery_dtbo_size); SHA_update(&ctx, &hdr->recovery_dtbo_size, sizeof(hdr->recovery_dtbo_size)); if(hdr->header_version > 1) { SHA_update(&ctx, dtb_data, hdr->dtb_size); SHA_update(&ctx, &hdr->dtb_size, sizeof(hdr->dtb_size)); } } sha = SHA_final(&ctx); memcpy(hdr->id, sha, SHA_DIGEST_SIZE > sizeof(hdr->id) ? sizeof(hdr->id) : SHA_DIGEST_SIZE); }
void AndroidFormat::updateSha1Hash(BootImageHeader *hdr) { SHA_CTX ctx; SHA_init(&ctx); SHA_update(&ctx, mI10e->kernelImage.data(), mI10e->kernelImage.size()); SHA_update(&ctx, reinterpret_cast<char *>(&hdr->kernel_size), sizeof(hdr->kernel_size)); SHA_update(&ctx, mI10e->ramdiskImage.data(), mI10e->ramdiskImage.size()); SHA_update(&ctx, reinterpret_cast<char *>(&hdr->ramdisk_size), sizeof(hdr->ramdisk_size)); if (!mI10e->secondImage.empty()) { SHA_update(&ctx, mI10e->secondImage.data(), mI10e->secondImage.size()); } // Bug in AOSP? AOSP's mkbootimg adds the second bootloader size to the SHA1 // hash even if it's 0 SHA_update(&ctx, reinterpret_cast<char *>(&hdr->second_size), sizeof(hdr->second_size)); if (!mI10e->dtImage.empty()) { SHA_update(&ctx, mI10e->dtImage.data(), mI10e->dtImage.size()); SHA_update(&ctx, reinterpret_cast<char *>(&hdr->dt_size), sizeof(hdr->dt_size)); } std::memset(hdr->id, 0, sizeof(hdr->id)); memcpy(hdr->id, SHA_final(&ctx), SHA_DIGEST_SIZE); std::string hexDigest = StringUtils::toHex( reinterpret_cast<const unsigned char *>(hdr->id), SHA_DIGEST_SIZE); FLOGD("Computed new ID hash: %s", hexDigest.c_str()); }
int sha_verify(FILE *f, uint8_t*sha0, size_t signed_len) { SHA_CTX ctx; SHA_init(&ctx); //FILE *f = fopen(name,"r"); if(NULL==f){ DEBUG("can not do sha verify with NULL file handle\n"); return -1; } unsigned char* buffer = malloc(BUFFER_SIZE); if (NULL==buffer){ DEBUG("failed to alloc memory for sha1 buffer\n"); //fclose(f); return -1; //VERIFY_FAILURE; } double frac = -1.0; size_t so_far = 0; // fseek(f, 0, SEEK_SET); while (so_far < signed_len) { size_t size = BUFFER_SIZE; if (signed_len - so_far < size) size = signed_len - so_far; if (fread(buffer, 1, size, f) != size) { DEBUG("failed to read data: %s\n", strerror(errno)); // fclose(f); free(buffer); buffer = NULL; return -1;//VERIFY_FAILURE; } SHA_update(&ctx, buffer, size); so_far += size; double df = so_far / (double)signed_len; if (df > frac + 0.02 || size == so_far) { frac = df; } } // fclose(f); free(buffer); const uint8_t* sha1 = SHA_final(&ctx); unsigned int i = 0;// = sizeof(sha1); printf("\n sha1 longth is [%d]\n",sizeof(ctx.buf)); for(i=0; i<sizeof(ctx.buf); i++) { //printf("%.2x",ctx.buf[i]); if(*sha1++ != *sha0++) { DEBUG("sha verify failed, not return when -1 currently\n"); return -1; } else DEBUG("sha verify success\n"); } printf("\n"); return 0; }
/* Convenience function */ const uint8_t* SHA_hash(const void *data, int len, uint8_t *digest) { const uint8_t *p; int i; SHA_CTX ctx; SHA_init(&ctx); SHA_update(&ctx, data, len); p = SHA_final(&ctx); for (i = 0; i < SHA_DIGEST_SIZE; ++i) { digest[i] = *p++; } return digest; }
static bool SecureNSModeUbootImageShaCheck(second_loader_hdr *hdr) { #ifndef SECUREBOOT_CRYPTO_EN uint8_t *sha; SHA_CTX ctx; int size = SHA_DIGEST_SIZE > hdr->hash_len ? hdr->hash_len : SHA_DIGEST_SIZE; SHA_init(&ctx); SHA_update(&ctx, (void *)hdr + sizeof(second_loader_hdr), hdr->loader_load_size); SHA_update(&ctx, &hdr->loader_load_addr, sizeof(hdr->loader_load_addr)); SHA_update(&ctx, &hdr->loader_load_size, sizeof(hdr->loader_load_size)); SHA_update(&ctx, &hdr->hash_len, sizeof(hdr->hash_len)); sha = SHA_final(&ctx); #else uint32 size; uint8 *sha; uint32 hwDataHash[8]; size = hdr->loader_load_size + sizeof(hdr->loader_load_size) \ + sizeof(hdr->loader_load_addr) + sizeof(hdr->hash_len); CryptoSHAInit(size, 160); /* rockchip's second level image. */ CryptoSHAStart((uint32 *)((void *)hdr + sizeof(second_loader_hdr)), hdr->loader_load_size); CryptoSHAStart((uint32 *)&hdr->loader_load_addr, sizeof(hdr->loader_load_addr)); CryptoSHAStart((uint32 *)&hdr->loader_load_size, sizeof(hdr->loader_load_size)); CryptoSHAStart((uint32 *)&hdr->hash_len, sizeof(hdr->hash_len)); CryptoSHAEnd(hwDataHash); sha = (uint8 *)hwDataHash; size = SHA_DIGEST_SIZE > hdr->hash_len ? hdr->hash_len : SHA_DIGEST_SIZE; #endif #if 0 int i = 0; printf("\nreal sha:\n"); for (i = 0;i < size;i++) { printf("%02x", (char)sha[i]); } printf("\nsha from image header:\n"); for (i = 0;i < size;i++) { printf("%02x", ((char*)hdr->hash)[i]); } printf("\n"); #endif return !memcmp(hdr->hash, sha, size); }
Value* RangeSha1Fn(const char* name, State* state, int argc, Expr* argv[]) { Value* blockdev_filename; Value* ranges; const uint8_t* digest = NULL; if (ReadValueArgs(state, argv, 2, &blockdev_filename, &ranges) < 0) { return NULL; } if (blockdev_filename->type != VAL_STRING) { ErrorAbort(state, "blockdev_filename argument to %s must be string", name); goto done; } if (ranges->type != VAL_STRING) { ErrorAbort(state, "ranges argument to %s must be string", name); goto done; } int fd = open(blockdev_filename->data, O_RDWR); if (fd < 0) { ErrorAbort(state, "failed to open %s: %s", blockdev_filename->data, strerror(errno)); goto done; } RangeSet* rs = parse_range(ranges->data); uint8_t buffer[BLOCKSIZE]; SHA_CTX ctx; SHA_init(&ctx); int i, j; for (i = 0; i < rs->count; ++i) { check_lseek(fd, (off64_t)rs->pos[i*2] * BLOCKSIZE, SEEK_SET); for (j = rs->pos[i*2]; j < rs->pos[i*2+1]; ++j) { readblock(fd, buffer, BLOCKSIZE); SHA_update(&ctx, buffer, BLOCKSIZE); } } digest = SHA_final(&ctx); close(fd); done: FreeValue(blockdev_filename); FreeValue(ranges); if (digest == NULL) { return StringValue(strdup("")); } else { return StringValue(PrintSha1(digest)); } }
int DxCore::sub_12FC(void *buf, int len, void *dest) { SHA_CTX ctx; SHA_init(&ctx); int left = len; int pos = 0; while (left > 0) { SHA_update(&ctx, (u8 *) buf + pos, left > 4096 ? 4096 : left); left -= 4096; pos += 4096; } const u8* ret = SHA_final(&ctx); memcpy(dest, ret, UUID_LEN); return 0; }
static void updateSha1Hash(BootImageHeader *hdr, const BootImageIntermediate *i10e, const MtkHeader *mtkKernelHdr, const MtkHeader *mtkRamdiskHdr, uint32_t kernelSize, uint32_t ramdiskSize) { SHA_CTX ctx; SHA_init(&ctx); if (mtkKernelHdr) { SHA_update(&ctx, mtkKernelHdr, sizeof(MtkHeader)); } SHA_update(&ctx, i10e->kernelImage.data(), i10e->kernelImage.size()); SHA_update(&ctx, reinterpret_cast<char *>(&kernelSize), sizeof(kernelSize)); if (mtkRamdiskHdr) { SHA_update(&ctx, mtkRamdiskHdr, sizeof(MtkHeader)); } SHA_update(&ctx, i10e->ramdiskImage.data(), i10e->ramdiskImage.size()); SHA_update(&ctx, reinterpret_cast<char *>(&ramdiskSize), sizeof(ramdiskSize)); if (!i10e->secondImage.empty()) { SHA_update(&ctx, i10e->secondImage.data(), i10e->secondImage.size()); } // Bug in AOSP? AOSP's mkbootimg adds the second bootloader size to the SHA1 // hash even if it's 0 SHA_update(&ctx, reinterpret_cast<char *>(&hdr->second_size), sizeof(hdr->second_size)); if (!i10e->dtImage.empty()) { SHA_update(&ctx, i10e->dtImage.data(), i10e->dtImage.size()); SHA_update(&ctx, reinterpret_cast<char *>(&hdr->dt_size), sizeof(hdr->dt_size)); } std::memset(hdr->id, 0, sizeof(hdr->id)); memcpy(hdr->id, SHA_final(&ctx), SHA_DIGEST_SIZE); std::string hexDigest = StringUtils::toHex( reinterpret_cast<const unsigned char *>(hdr->id), SHA_DIGEST_SIZE); LOGD("Computed new ID hash: %s", hexDigest.c_str()); }
int DxCore::sub_1370(const char *filepath, void *dest) { FILE *fp = fopen(filepath, "rb"); if (fp == NULL) { return -1; } SHA_CTX ctx; u8 buf[4096]; int n = -1; SHA_init(&ctx); while ((n = fread(buf, 1, 4096, fp)) > 0) { SHA_update(&ctx, buf, n); } fclose(fp); const u8* ret = SHA_final(&ctx); memcpy(dest, ret, UUID_LEN); return 0; }
/* get SHA1 sum of all static regions described by the flashmap and copy into *digest (which will be allocated and must be freed by the caller), */ int fmap_get_csum(const uint8_t *image, unsigned int image_len, uint8_t **digest) { int i; struct fmap *fmap; int fmap_offset; SHA_CTX ctx; if ((image == NULL)) return -1; if ((fmap_offset = fmap_find(image, image_len)) < 0) return -1; fmap = (struct fmap *)(image + fmap_offset); SHA_init(&ctx); /* Iterate through flash map and calculate the checksum piece-wise. */ for (i = 0; i < fmap->nareas; i++) { /* skip non-static areas */ if (!(fmap->areas[i].flags & FMAP_AREA_STATIC)) continue; /* sanity check the offset */ if (fmap->areas[i].size + fmap->areas[i].offset > image_len) { fprintf(stderr, "(%s) invalid parameter detected in area %d\n", __func__, i); return -1; } SHA_update(&ctx, image + fmap->areas[i].offset, fmap->areas[i].size); } SHA_final(&ctx); *digest = malloc(SHA_DIGEST_SIZE); memcpy(*digest, ctx.buf, SHA_DIGEST_SIZE); return SHA_DIGEST_SIZE; }
char * util_hash_sha_image_file_new(const char *image_file) { FILE *fp = NULL; SHA_CTX ctx; SHA_init(&ctx); if (!(fp = fopen(image_file, "rb"))) { ERROR_ERRNO("Error in file hasing, cannot open %s", image_file); return NULL; } int len = 0; unsigned char buf[SIGN_HASH_BUFFER_SIZE]; while ((len = fread(buf, 1, sizeof(buf), fp)) > 0) { SHA_update(&ctx, buf, len); } fclose(fp); return convert_bin_to_hex_new(SHA_final(&ctx), SHA_DIGEST_SIZE); }
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, Value** patch_data) { printf("\napplying patch to %s\n", source_filename); if (target_filename[0] == '-' && target_filename[1] == '\0') { target_filename = source_filename; } uint8_t target_sha1[SHA_DIGEST_SIZE]; if (ParseSha1(target_sha1_str, target_sha1) != 0) { printf("failed to parse tgt-sha1 \"%s\"\n", target_sha1_str); return 1; } FileContents copy_file; FileContents source_file; const Value* source_patch_value = NULL; const Value* copy_patch_value = NULL; int made_copy = 0; // We try to load the target file into the source_file object. if (LoadFileContents(target_filename, &source_file, RETOUCH_DO_MASK) == 0) { if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 0) { // The early-exit case: the patch was already applied, this file // has the desired hash, nothing for us to do. printf("\"%s\" is already target; no patch needed\n", target_filename); return 0; } } if (source_file.data == NULL || (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); LoadFileContents(source_filename, &source_file, RETOUCH_DO_MASK); } if (source_file.data != NULL) { int to_use = FindMatchingPatch(source_file.sha1, patch_sha1_str, num_patches); if (to_use >= 0) { source_patch_value = patch_data[to_use]; } } if (source_patch_value == NULL) { free(source_file.data); printf("source file is bad; trying copy\n"); if (LoadFileContents(CACHE_TEMP_SOURCE, ©_file, RETOUCH_DO_MASK) < 0) { // fail. printf("failed to read copy file\n"); return 1; } int to_use = FindMatchingPatch(copy_file.sha1, patch_sha1_str, num_patches); if (to_use >= 0) { copy_patch_value = patch_data[to_use]; } if (copy_patch_value == NULL) { // fail. printf("copy file doesn't match source SHA-1s either\n"); return 1; } } int retry = 1; SHA_CTX ctx; int output; MemorySinkInfo msi; FileContents* source_to_use; char* outname; // 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'; } else { strcpy(target_fs, target_filename); } do { // Is there enough room in the target filesystem to hold the patched // file? if (strncmp(target_filename, "EMMC:", 5) == 0) { // 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.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); enough_space = (free_space > (256 << 10)) && // 256k (two-block) minimum (free_space > (target_size * 3 / 2)); // 50% margin of error printf("target %ld bytes; free space %ld bytes; retry %d; enough %d\n", (long)target_size, (long)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.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); printf("(now %ld bytes free for target)\n", (long)free_space); } } const Value* patch; if (source_patch_value != NULL) { source_to_use = &source_file; patch = source_patch_value; } else { source_to_use = ©_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, "EMMC:", 5) == 0) { // We store the decoded output in memory. msi.buffer = malloc(target_size); if (msi.buffer == NULL) { printf("failed to alloc %ld bytes for output\n", (long)target_size); return 1; } msi.pos = 0; msi.size = target_size; sink = MemorySink; token = &msi; } else { // We write the decoded output to "<tgt-file>.patch". outname = (char*)malloc(strlen(target_filename) + 10); strcpy(outname, target_filename); strcat(outname, ".patch"); output = 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)); return 1; } sink = FileSink; token = &output; } char* header = patch->data; ssize_t header_bytes_read = patch->size; SHA_init(&ctx); int result; if (header_bytes_read >= 8 && memcmp(header, "BSDIFF40", 8) == 0) { 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) { result = ApplyImagePatch(source_to_use->data, source_to_use->size, patch, sink, token, &ctx); } else { printf("Unknown patch file format\n"); return 1; } if (output >= 0) { fsync(output); close(output); } if (result != 0) { if (retry == 0) { printf("applying patch failed\n"); return result != 0; } else { printf("applying patch failed; retrying\n"); } if (outname != NULL) { unlink(outname); } } else { // succeeded; no need to retry break; } } while (retry-- > 0); const uint8_t* current_target_sha1 = SHA_final(&ctx); if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_SIZE) != 0) { printf("patch did not produce expected sha1\n"); return 1; } if (output < 0) { // Copy the temp file to the partition. if (WriteToPartition(msi.buffer, msi.pos, 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)); 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)); return 1; } // Finally, rename the .patch file to replace the target file. if (rename(outname, target_filename) != 0) { printf("rename of .patch to \"%s\" failed: %s\n", target_filename, 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); // Success! return 0; }
static int LoadPartitionContents(const char* filename, FileContents* file) { char* copy = strdup(filename); const char* magic = strtok(copy, ":"); enum PartitionType type; if (strcmp(magic, "EMMC") == 0) { type = EMMC; } else { printf("LoadPartitionContents called with bad filename (%s)\n", filename); return -1; } const char* partition = strtok(NULL, ":"); int i; int colons = 0; for (i = 0; filename[i] != '\0'; ++i) { if (filename[i] == ':') { ++colons; } } if (colons < 3 || colons%2 == 0) { printf("LoadPartitionContents called with bad filename (%s)\n", filename); } int pairs = (colons-1)/2; // # of (size,sha1) pairs in filename int* index = malloc(pairs * sizeof(int)); size_t* size = malloc(pairs * sizeof(size_t)); char** sha1sum = malloc(pairs * sizeof(char*)); for (i = 0; i < pairs; ++i) { const char* size_str = strtok(NULL, ":"); size[i] = strtol(size_str, NULL, 10); if (size[i] == 0) { printf("LoadPartitionContents called with bad size (%s)\n", filename); return -1; } sha1sum[i] = strtok(NULL, ":"); index[i] = i; } // sort the index[] array so it indexes the pairs in order of // increasing size. size_array = size; qsort(index, pairs, sizeof(int), compare_size_indices); FILE* dev = NULL; switch (type) { case EMMC: dev = fopen(partition, "rb"); if (dev == NULL) { printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno)); return -1; } } SHA_CTX sha_ctx; SHA_init(&sha_ctx); uint8_t parsed_sha[SHA_DIGEST_SIZE]; // allocate enough memory to hold the largest size. file->data = malloc(size[index[pairs-1]]); char* p = (char*)file->data; file->size = 0; // # bytes read so far for (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; if (next > 0) { switch (type) { case EMMC: read = fread(p, 1, next, dev); break; } if (next != read) { printf("short read (%d bytes of %d) for partition \"%s\"\n", read, next, partition); free(file->data); file->data = NULL; return -1; } SHA_update(&sha_ctx, p, read); file->size += 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)); const uint8_t* sha_so_far = SHA_final(&temp_ctx); if (ParseSha1(sha1sum[index[i]], parsed_sha) != 0) { printf("failed to parse sha1 %s in %s\n", sha1sum[index[i]], filename); free(file->data); file->data = NULL; return -1; } if (memcmp(sha_so_far, parsed_sha, SHA_DIGEST_SIZE) == 0) { // we have a match. stop reading the partition; we'll return // the data we've read so far. printf("partition read matched size %d sha %s\n", size[index[i]], sha1sum[index[i]]); break; } p += read; } switch (type) { case EMMC: fclose(dev); break; } if (i == pairs) { // 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; } const uint8_t* sha_final = SHA_final(&sha_ctx); for (i = 0; i < SHA_DIGEST_SIZE; ++i) { file->sha1[i] = sha_final[i]; } // Fake some stat() info. file->st.st_mode = 0644; file->st.st_uid = 0; file->st.st_gid = 0; free(copy); free(index); free(size); free(sha1sum); return 0; }
int main(int argc, char **argv) { boot_img_hdr hdr; char *kernel_fn = 0; void *kernel_data = 0; char *ramdisk_fn = 0; void *ramdisk_data = 0; char *second_fn = 0; void *second_data = 0; char *cmdline = ""; char *bootimg = 0; char *board = ""; unsigned pagesize = 2048; unsigned saddr = 0; int fd; SHA_CTX ctx; uint8_t* sha; argc--; argv++; memset(&hdr, 0, sizeof(hdr)); /* default load addresses */ hdr.kernel_addr = 0x10008000; hdr.ramdisk_addr = 0x11000000; hdr.second_addr = 0x10F00000; hdr.tags_addr = 0x10000100; hdr.page_size = pagesize; while(argc > 0){ char *arg = argv[0]; char *val = argv[1]; if(argc < 2) { return usage(); } argc -= 2; argv += 2; if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) { bootimg = val; } else if(!strcmp(arg, "--kernel")) { kernel_fn = val; } else if(!strcmp(arg, "--ramdisk")) { ramdisk_fn = val; } else if(!strcmp(arg, "--second")) { second_fn = val; } else if(!strcmp(arg, "--cmdline")) { cmdline = val; } else if(!strcmp(arg, "--base")) { unsigned base = strtoul(val, 0, 16); hdr.kernel_addr = base + 0x00008000; hdr.ramdisk_addr = base + 0x01000000; hdr.second_addr = base + 0x00F00000; hdr.tags_addr = base + 0x00000100; } else if(!strcmp(arg, "--board")) { board = val; } else { return usage(); } } if(bootimg == 0) { fprintf(stderr,"error: no output filename specified\n"); return usage(); } if(kernel_fn == 0) { fprintf(stderr,"error: no kernel image specified\n"); return usage(); } if(ramdisk_fn == 0) { fprintf(stderr,"error: no ramdisk image specified\n"); return usage(); } if(strlen(board) >= BOOT_NAME_SIZE) { fprintf(stderr,"error: board name too large\n"); return usage(); } strcpy(hdr.name, board); #ifndef GENERIC hdr.kernel_addr = KERNEL_ADDR; hdr.ramdisk_addr = RAMDISK_ADDR; if(saddr) { hdr.second_addr = 0x00300000; } else { hdr.second_addr = SECONDARY_ADDR; } hdr.tags_addr = TAGS_ADDR; hdr.page_size = pagesize; #else hdr.kernel_addr = 0x208000; hdr.ramdisk_addr = 0x1200000; if(saddr) { hdr.second_addr = 0x00300000; } else { hdr.second_addr = 0x1100000; } hdr.tags_addr = 0x10000100; hdr.page_size = pagesize; #endif memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE); if(strlen(cmdline) > (BOOT_ARGS_SIZE - 1)) { fprintf(stderr,"error: kernel commandline too large\n"); return 1; } strcpy((char*)hdr.cmdline, cmdline); kernel_data = load_file(kernel_fn, &hdr.kernel_size); if(kernel_data == 0) { fprintf(stderr,"error: could not load kernel '%s'\n", kernel_fn); return 1; } if(!strcmp(ramdisk_fn,"NONE")) { ramdisk_data = 0; hdr.ramdisk_size = 0; } else { ramdisk_data = load_file(ramdisk_fn, &hdr.ramdisk_size); if(ramdisk_data == 0) { fprintf(stderr,"error: could not load ramdisk '%s'\n", ramdisk_fn); return 1; } } if(second_fn) { second_data = load_file(second_fn, &hdr.second_size); if(second_data == 0) { fprintf(stderr,"error: could not load secondstage '%s'\n", second_fn); return 1; } } /* put a hash of the contents in the header so boot images can be * differentiated based on their first 2k. */ SHA_init(&ctx); SHA_update(&ctx, kernel_data, hdr.kernel_size); SHA_update(&ctx, &hdr.kernel_size, sizeof(hdr.kernel_size)); SHA_update(&ctx, ramdisk_data, hdr.ramdisk_size); SHA_update(&ctx, &hdr.ramdisk_size, sizeof(hdr.ramdisk_size)); SHA_update(&ctx, second_data, hdr.second_size); SHA_update(&ctx, &hdr.second_size, sizeof(hdr.second_size)); sha = SHA_final(&ctx); memcpy(hdr.id, sha, SHA_DIGEST_SIZE > sizeof(hdr.id) ? sizeof(hdr.id) : SHA_DIGEST_SIZE); fd = open(bootimg, O_CREAT | O_TRUNC | O_WRONLY, 0644); if(fd < 0) { fprintf(stderr,"error: could not create '%s'\n", bootimg); return 1; } if(write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) goto fail; if(write_padding(fd, pagesize, sizeof(hdr))) goto fail; if(write_page_padding(fd, pagesize, sizeof(hdr))) goto fail; if(write(fd, kernel_data, hdr.kernel_size) != hdr.kernel_size) goto fail; if(write_padding(fd, pagesize, hdr.kernel_size)) goto fail; if(write_page_padding(fd, pagesize, hdr.kernel_size)) goto fail; if(write(fd, ramdisk_data, hdr.ramdisk_size) != hdr.ramdisk_size) goto fail; if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail; if(write_page_padding(fd, pagesize, hdr.ramdisk_size)) goto fail; if(second_data) { if(write(fd, second_data, hdr.second_size) != hdr.second_size) goto fail; if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail; if(write_page_padding(fd, pagesize, hdr.ramdisk_size)) goto fail; } return 0; fail: unlink(bootimg); close(fd); fprintf(stderr,"error: failed writing '%s': %s\n", bootimg, strerror(errno)); return 1; }
int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKeys) { ui->SetProgress(0.0); FILE* f = fopen(path, "rb"); if (f == NULL) { LOGE("failed to open %s (%s)\n", path, strerror(errno)); return VERIFY_FAILURE; } // An archive with a whole-file signature will end in six bytes: // // (2-byte signature start) $ff $ff (2-byte comment size) // // (As far as the ZIP format is concerned, these are part of the // archive comment.) We start by reading this footer, this tells // us how far back from the end we have to start reading to find // the whole comment. #define FOOTER_SIZE 6 if (fseek(f, -FOOTER_SIZE, SEEK_END) != 0) { LOGE("failed to seek in %s (%s)\n", path, strerror(errno)); fclose(f); return VERIFY_FAILURE; } unsigned char footer[FOOTER_SIZE]; if (fread(footer, 1, FOOTER_SIZE, f) != FOOTER_SIZE) { LOGE("failed to read footer from %s (%s)\n", path, strerror(errno)); fclose(f); return VERIFY_FAILURE; } if (footer[2] != 0xff || footer[3] != 0xff) { fclose(f); return VERIFY_FAILURE; } size_t comment_size = footer[4] + (footer[5] << 8); size_t signature_start = footer[0] + (footer[1] << 8); LOGI("comment is %d bytes; signature %d bytes from end\n", comment_size, signature_start); if (signature_start - FOOTER_SIZE < RSANUMBYTES) { // "signature" block isn't big enough to contain an RSA block. LOGE("signature is too short\n"); fclose(f); return VERIFY_FAILURE; } #define EOCD_HEADER_SIZE 22 // The end-of-central-directory record is 22 bytes plus any // comment length. size_t eocd_size = comment_size + EOCD_HEADER_SIZE; if (fseek(f, -eocd_size, SEEK_END) != 0) { LOGE("failed to seek in %s (%s)\n", path, strerror(errno)); fclose(f); return VERIFY_FAILURE; } // Determine how much of the file is covered by the signature. // This is everything except the signature data and length, which // includes all of the EOCD except for the comment length field (2 // bytes) and the comment data. size_t signed_len = ftell(f) + EOCD_HEADER_SIZE - 2; unsigned char* eocd = (unsigned char*)malloc(eocd_size); if (eocd == NULL) { LOGE("malloc for EOCD record failed\n"); fclose(f); return VERIFY_FAILURE; } if (fread(eocd, 1, eocd_size, f) != eocd_size) { LOGE("failed to read eocd from %s (%s)\n", path, strerror(errno)); fclose(f); return VERIFY_FAILURE; } // If this is really is the EOCD record, it will begin with the // magic number $50 $4b $05 $06. if (eocd[0] != 0x50 || eocd[1] != 0x4b || eocd[2] != 0x05 || eocd[3] != 0x06) { LOGE("signature length doesn't match EOCD marker\n"); fclose(f); return VERIFY_FAILURE; } size_t i; for (i = 4; i < eocd_size-3; ++i) { if (eocd[i ] == 0x50 && eocd[i+1] == 0x4b && eocd[i+2] == 0x05 && eocd[i+3] == 0x06) { // if the sequence $50 $4b $05 $06 appears anywhere after // the real one, minzip will find the later (wrong) one, // which could be exploitable. Fail verification if // this sequence occurs anywhere after the real one. LOGE("EOCD marker occurs after start of EOCD\n"); fclose(f); return VERIFY_FAILURE; } } #define BUFFER_SIZE 4096 SHA_CTX ctx; SHA_init(&ctx); unsigned char* buffer = (unsigned char*)malloc(BUFFER_SIZE); if (buffer == NULL) { LOGE("failed to alloc memory for sha1 buffer\n"); fclose(f); return VERIFY_FAILURE; } double frac = -1.0; size_t so_far = 0; fseek(f, 0, SEEK_SET); while (so_far < signed_len) { size_t size = BUFFER_SIZE; if (signed_len - so_far < size) size = signed_len - so_far; if (fread(buffer, 1, size, f) != size) { LOGE("failed to read data from %s (%s)\n", path, strerror(errno)); fclose(f); return VERIFY_FAILURE; } SHA_update(&ctx, buffer, size); so_far += size; double f = so_far / (double)signed_len; if (f > frac + 0.02 || size == so_far) { ui->SetProgress(f); frac = f; } } fclose(f); free(buffer); const uint8_t* sha1 = SHA_final(&ctx); for (i = 0; i < numKeys; ++i) { // The 6 bytes is the "(signature_start) $ff $ff (comment_size)" that // the signing tool appends after the signature itself. if (RSA_verify(pKeys+i, eocd + eocd_size - 6 - RSANUMBYTES, RSANUMBYTES, sha1)) { LOGI("whole-file signature verified against key %d\n", i); free(eocd); return VERIFY_SUCCESS; } else { LOGI("failed to verify against key %d\n", i); } } free(eocd); LOGE("failed to verify whole-file signature\n"); return VERIFY_FAILURE; }
static int LoadPartitionContents(const char* filename, FileContents* file) { char* copy = strdup(filename); const char* magic = strtok(copy, ":"); enum PartitionType type; #if 0 //wschen 2012-05-24 if (strcmp(magic, "MTD") == 0) { type = MTD; } else if (strcmp(magic, "EMMC") == 0) { type = EMMC; } else { printf("LoadPartitionContents called with bad filename (%s)\n", filename); return -1; } #else switch (phone_type()) { case NAND_TYPE: type = MTD; break; case EMMC_TYPE: type = EMMC; break; default: printf("LoadPartitionContents called with bad filename (%s)\n", filename); return -1; } #endif const char* partition = strtok(NULL, ":"); int i; int colons = 0; for (i = 0; filename[i] != '\0'; ++i) { if (filename[i] == ':') { ++colons; } } if (colons < 3 || colons%2 == 0) { printf("LoadPartitionContents called with bad filename (%s)\n", filename); } int pairs = (colons-1)/2; // # of (size,sha1) pairs in filename int* index = malloc(pairs * sizeof(int)); size_t* size = malloc(pairs * sizeof(size_t)); char** sha1sum = malloc(pairs * sizeof(char*)); for (i = 0; i < pairs; ++i) { const char* size_str = strtok(NULL, ":"); size[i] = strtol(size_str, NULL, 10); if (size[i] == 0) { printf("LoadPartitionContents called with bad size (%s)\n", filename); return -1; } sha1sum[i] = strtok(NULL, ":"); index[i] = i; } // sort the index[] array so it indexes the pairs in order of // increasing size. size_array = size; qsort(index, pairs, sizeof(int), compare_size_indices); MtdReadContext* ctx = NULL; int dev = -1; switch (type) { case MTD: if (!mtd_partitions_scanned) { mtd_scan_partitions(); mtd_partitions_scanned = 1; } 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: printf("open emmc partition \"%s\"\n", partition); if (!strcmp(partition, "boot")) { dev = open("/dev/bootimg", O_RDWR); if (dev == -1) { printf("failed to open emmc partition \"/dev/bootimg\": %s\n", strerror(errno)); return -1; } } else { char dev_name[32]; strcpy(dev_name, "/dev/"); strcat(dev_name, partition); dev = open(dev_name, O_RDWR); if (dev == -1) { printf("failed to open emmc partition \"%s\": %s\n", dev_name, strerror(errno)); return -1; } } break; } SHA_CTX sha_ctx; SHA_init(&sha_ctx); uint8_t parsed_sha[SHA_DIGEST_SIZE]; // allocate enough memory to hold the largest size. file->data = malloc(size[index[pairs-1]]); char* p = (char*)file->data; file->size = 0; // # bytes read so far for (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_cnt = 0; if (next > 0) { switch (type) { case MTD: read_cnt = mtd_read_data(ctx, p, next); break; case EMMC: read_cnt = read(dev, p, next); break; } if (next != read_cnt) { printf("short read (%d bytes of %d) for partition \"%s\"\n", read_cnt, next, partition); free(file->data); file->data = NULL; return -1; } SHA_update(&sha_ctx, p, read_cnt); file->size += read_cnt; } // 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)); const uint8_t* sha_so_far = SHA_final(&temp_ctx); if (ParseSha1(sha1sum[index[i]], parsed_sha) != 0) { printf("failed to parse sha1 %s in %s\n", sha1sum[index[i]], filename); free(file->data); file->data = NULL; return -1; } if (memcmp(sha_so_far, parsed_sha, SHA_DIGEST_SIZE) == 0) { // we have a match. stop reading the partition; we'll return // the data we've read so far. printf("partition read matched size %d sha %s\n", size[index[i]], sha1sum[index[i]]); break; } p += read_cnt; } switch (type) { case MTD: mtd_read_close(ctx); break; case EMMC: close(dev); break; } if (i == pairs) { // 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; } const uint8_t* sha_final = SHA_final(&sha_ctx); for (i = 0; i < SHA_DIGEST_SIZE; ++i) { file->sha1[i] = sha_final[i]; } // Fake some stat() info. file->st.st_mode = 0644; file->st.st_uid = 0; file->st.st_gid = 0; free(copy); free(index); free(size); free(sha1sum); return 0; }
int applypatch(int argc, char** argv) { if (argc < 2) { return 2; } if (strncmp(argv[1], "-l", 3) == 0) { return ShowLicenses(); } if (strncmp(argv[1], "-c", 3) == 0) { return CheckMode(argc, argv); } if (strncmp(argv[1], "-s", 3) == 0) { if (argc != 3) { return 2; } size_t bytes = strtol(argv[2], NULL, 10); if (MakeFreeSpaceOnCache(bytes) < 0) { printf("unable to make %ld bytes available on /cache\n", (long)bytes); return 1; } else { return 0; } } uint8_t target_sha1[SHA_DIGEST_SIZE]; const char* source_filename = argv[1]; const char* target_filename = argv[2]; if (target_filename[0] == '-' && target_filename[1] == '\0') { target_filename = source_filename; } if (ParseSha1(argv[3], target_sha1) != 0) { fprintf(stderr, "failed to parse tgt-sha1 \"%s\"\n", argv[3]); return 1; } unsigned long target_size = strtoul(argv[4], NULL, 0); int num_patches; Patch* patches; if (ParseShaArgs(argc-5, argv+5, &patches, &num_patches) < 0) { return 1; } FileContents copy_file; FileContents source_file; const char* source_patch_filename = NULL; const char* copy_patch_filename = NULL; int made_copy = 0; // 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) { // The early-exit case: the patch was already applied, this file // has the desired hash, nothing for us to do. fprintf(stderr, "\"%s\" is already target; no patch needed\n", target_filename); return 0; } } if (source_file.data == NULL || (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); LoadFileContents(source_filename, &source_file); } if (source_file.data != NULL) { const Patch* to_use = FindMatchingPatch(source_file.sha1, patches, num_patches); if (to_use != NULL) { source_patch_filename = to_use->patch_filename; } } if (source_patch_filename == NULL) { free(source_file.data); fprintf(stderr, "source file is bad; trying copy\n"); if (LoadFileContents(CACHE_TEMP_SOURCE, ©_file) < 0) { // fail. fprintf(stderr, "failed to read copy file\n"); return 1; } const Patch* to_use = FindMatchingPatch(copy_file.sha1, patches, num_patches); if (to_use != NULL) { copy_patch_filename = to_use->patch_filename; } if (copy_patch_filename == NULL) { // fail. fprintf(stderr, "copy file doesn't match source SHA-1s either\n"); return 1; } } // Is there enough room in the target filesystem to hold the patched // file? if (strncmp(target_filename, "MTD:", 4) == 0) { // If the target is an MTD 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 MTD // write is interrupted. if (MakeFreeSpaceOnCache(source_file.size) < 0) { fprintf(stderr, "not enough free space on /cache\n"); return 1; } if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) { fprintf(stderr, "failed to back up source file\n"); return 1; } made_copy = 1; } else { // 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 = strdup(target_filename); char* slash = strchr(target_fs+1, '/'); if (slash != NULL) { *slash = '\0'; } size_t free_space = FreeSpaceForFile(target_fs); int enough_space = free_space > (target_size * 3 / 2); // 50% margin of error printf("target %ld bytes; free space %ld bytes; enough %d\n", (long)target_size, (long)free_space, enough_space); if (!enough_space && source_patch_filename != 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, "MTD:", 4) == 0) { // It's impossible to free space on the target filesystem by // deleting the source if the source is an MTD partition. If // we're ever in a state where we need to do this, fail. fprintf(stderr, "not enough free space for target but source is MTD\n"); return 1; } if (MakeFreeSpaceOnCache(source_file.size) < 0) { fprintf(stderr, "not enough free space on /cache\n"); return 1; } if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) { fprintf(stderr, "failed to back up source file\n"); return 1; } made_copy = 1; unlink(source_filename); size_t free_space = FreeSpaceForFile(target_fs); printf("(now %ld bytes free for target)\n", (long)free_space); } } FileContents* source_to_use; const char* patch_filename; if (source_patch_filename != NULL) { source_to_use = &source_file; patch_filename = source_patch_filename; } else { source_to_use = ©_file; patch_filename = copy_patch_filename; } char* outname = NULL; FILE* output = NULL; MemorySinkInfo msi; SinkFn sink = NULL; void* token = NULL; if (strncmp(target_filename, "MTD:", 4) == 0) { // We store the decoded output in memory. msi.buffer = malloc(target_size); if (msi.buffer == NULL) { fprintf(stderr, "failed to alloc %ld bytes for output\n", (long)target_size); return 1; } msi.pos = 0; msi.size = target_size; sink = MemorySink; token = &msi; } else { // We write the decoded output to "<tgt-file>.patch". outname = (char*)malloc(strlen(target_filename) + 10); strcpy(outname, target_filename); strcat(outname, ".patch"); output = fopen(outname, "wb"); if (output == NULL) { fprintf(stderr, "failed to open output file %s: %s\n", outname, strerror(errno)); return 1; } sink = FileSink; token = output; } #define MAX_HEADER_LENGTH 8 unsigned char header[MAX_HEADER_LENGTH]; FILE* patchf = fopen(patch_filename, "rb"); if (patchf == NULL) { fprintf(stderr, "failed to open patch file %s: %s\n", patch_filename, strerror(errno)); return 1; } int header_bytes_read = fread(header, 1, MAX_HEADER_LENGTH, patchf); fclose(patchf); SHA_CTX ctx; SHA_init(&ctx); if (header_bytes_read >= 4 && header[0] == 0xd6 && header[1] == 0xc3 && header[2] == 0xc4 && header[3] == 0) { // xdelta3 patches begin "VCD" (with the high bits set) followed // by a zero byte (the version number). fprintf(stderr, "error: xdelta3 patches no longer supported\n"); return 1; } else if (header_bytes_read >= 8 && memcmp(header, "BSDIFF40", 8) == 0) { int result = ApplyBSDiffPatch(source_to_use->data, source_to_use->size, patch_filename, 0, sink, token, &ctx); if (result != 0) { fprintf(stderr, "ApplyBSDiffPatch failed\n"); return result; } } else if (header_bytes_read >= 8 && memcmp(header, "IMGDIFF", 7) == 0 && (header[7] == '1' || header[7] == '2')) { int result = ApplyImagePatch(source_to_use->data, source_to_use->size, patch_filename, sink, token, &ctx); if (result != 0) { fprintf(stderr, "ApplyImagePatch failed\n"); return result; } } else { fprintf(stderr, "Unknown patch file format\n"); return 1; } if (output != NULL) { fflush(output); fsync(fileno(output)); fclose(output); } const uint8_t* current_target_sha1 = SHA_final(&ctx); if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_SIZE) != 0) { fprintf(stderr, "patch did not produce expected sha1\n"); return 1; } if (output == NULL) { // Copy the temp file to the MTD partition. if (WriteToMTDPartition(msi.buffer, msi.pos, target_filename) != 0) { fprintf(stderr, "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) { fprintf(stderr, "chmod of \"%s\" failed: %s\n", outname, strerror(errno)); return 1; } if (chown(outname, source_to_use->st.st_uid, source_to_use->st.st_gid) != 0) { fprintf(stderr, "chown of \"%s\" failed: %s\n", outname, strerror(errno)); return 1; } // Finally, rename the .patch file to replace the target file. if (rename(outname, target_filename) != 0) { fprintf(stderr, "rename of .patch to \"%s\" failed: %s\n", target_filename, 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); // Success! return 0; }
static bool SecureRKModeVerifyUbootImage(second_loader_hdr *uboothdr) { int i; uint32 size; uint8 *dataHash; uint32 rsaResult[8]; uint32 hwDataHash[8]; uint8 *rsahash = (uint8 *)rsaResult; BOOT_HEADER *pkeyHead = (BOOT_HEADER *)g_rsa_key_buf; #if 0 { int k = 0; char *buf = uboothdr->hash; printf("Second Loader Head: magic = %s, sign tag = 0x%x, hash len = %d\n", uboothdr->magic, uboothdr->signTag, uboothdr->hash_len); printf("Second Loader Head: hash data:\n"); for (k = 0; k < uboothdr->hash_len; k++) { printf("%02x", buf[k]); } printf("\n"); printf("Loader addr = 0x%x, size = 0x%x\n", uboothdr->loader_load_addr, uboothdr->loader_load_size); } #endif /* verify uboot iamge. */ if (memcmp(uboothdr->magic, RK_UBOOT_MAGIC, sizeof(RK_UBOOT_MAGIC)) != 0) { return false; } if ((uboothdr->signTag != RK_UBOOT_SIGN_TAG) \ && (uboothdr->hash_len != 20) && (uboothdr->hash_len != 32)) { return false; } #if 0 { SHA_CTX ctx; SHA_init(&ctx); SHA_update(&ctx, (void *)uboothdr + sizeof(second_loader_hdr), uboothdr->loader_load_size); SHA_update(&ctx, &uboothdr->loader_load_addr, sizeof(uboothdr->loader_load_addr)); SHA_update(&ctx, &uboothdr->loader_load_size, sizeof(uboothdr->loader_load_size)); SHA_update(&ctx, &uboothdr->hash_len, sizeof(uboothdr->hash_len)); dataHash = SHA_final(&ctx); int k = 0; char *buf = dataHash; printf("Soft Calc Image hash data:\n"); for (k = 0; k < uboothdr->hash_len; k++) { printf("%02x", buf[k]); } printf("\n"); } #endif size = uboothdr->loader_load_size + sizeof(uboothdr->loader_load_size) \ + sizeof(uboothdr->loader_load_addr) + sizeof(uboothdr->hash_len); CryptoRSAInit((uint32 *)(uboothdr->rsaHash), pkeyHead->RSA_N, pkeyHead->RSA_E, pkeyHead->RSA_C); CryptoSHAInit(size, 160); /* rockchip's second level image. */ CryptoSHAStart((uint32 *)((void *)uboothdr + sizeof(second_loader_hdr)), uboothdr->loader_load_size); CryptoSHAStart((uint32 *)&uboothdr->loader_load_addr, sizeof(uboothdr->loader_load_addr)); CryptoSHAStart((uint32 *)&uboothdr->loader_load_size, sizeof(uboothdr->loader_load_size)); CryptoSHAStart((uint32 *)&uboothdr->hash_len, sizeof(uboothdr->hash_len)); CryptoSHAEnd(hwDataHash); CryptoRSAEnd(rsaResult); dataHash = (uint8 *)hwDataHash; #if 0 { int k = 0; char *buf = dataHash; printf("Crypto Calc Image hash data:\n"); for (k = 0; k < uboothdr->hash_len; k++) { printf("%02x", buf[k]); } printf("\n"); } #endif /* check the hash of image */ if (memcmp(uboothdr->hash, hwDataHash, uboothdr->hash_len) != 0) { return false; } /* check the sign of hash */ for (i = 0; i < 20; i++) { if (rsahash[19-i] != dataHash[i]) { return false; } } return true; }
// Load the contents of an MTD partition into the provided // FileContents. filename should be a string of the form // "MTD:<partition_name>:<size_1>:<sha1_1>:<size_2>:<sha1_2>:...". // The smallest size_n bytes for which that prefix of the mtd 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. // // This complexity is needed because if an OTA installation is // interrupted, the partition might contain either the source or the // target data, which might be of different lengths. We need to know // the length in order to read from MTD (there is no "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. int LoadMTDContents(const char* filename, FileContents* file) { char* copy = strdup(filename); const char* magic = strtok(copy, ":"); if (strcmp(magic, "MTD") != 0) { fprintf(stderr, "LoadMTDContents called with bad filename (%s)\n", filename); return -1; } const char* partition = strtok(NULL, ":"); int i; int colons = 0; for (i = 0; filename[i] != '\0'; ++i) { if (filename[i] == ':') { ++colons; } } if (colons < 3 || colons%2 == 0) { fprintf(stderr, "LoadMTDContents called with bad filename (%s)\n", filename); } int pairs = (colons-1)/2; // # of (size,sha1) pairs in filename int* index = malloc(pairs * sizeof(int)); size_t* size = malloc(pairs * sizeof(size_t)); char** sha1sum = malloc(pairs * sizeof(char*)); for (i = 0; i < pairs; ++i) { const char* size_str = strtok(NULL, ":"); size[i] = strtol(size_str, NULL, 10); if (size[i] == 0) { fprintf(stderr, "LoadMTDContents called with bad size (%s)\n", filename); return -1; } sha1sum[i] = strtok(NULL, ":"); index[i] = i; } // sort the index[] array so it indexes the pairs in order of // increasing size. size_array = size; qsort(index, pairs, sizeof(int), compare_size_indices); if (!mtd_partitions_scanned) { mtd_scan_partitions(); mtd_partitions_scanned = 1; } const MtdPartition* mtd = mtd_find_partition_by_name(partition); if (mtd == NULL) { fprintf(stderr, "mtd partition \"%s\" not found (loading %s)\n", partition, filename); return -1; } MtdReadContext* ctx = mtd_read_partition(mtd); if (ctx == NULL) { fprintf(stderr, "failed to initialize read of mtd partition \"%s\"\n", partition); return -1; } SHA_CTX sha_ctx; SHA_init(&sha_ctx); uint8_t parsed_sha[SHA_DIGEST_SIZE]; // allocate enough memory to hold the largest size. file->data = malloc(size[index[pairs-1]]); char* p = (char*)file->data; file->size = 0; // # bytes read so far for (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; if (next > 0) { read = mtd_read_data(ctx, p, next); if (next != read) { fprintf(stderr, "short read (%d bytes of %d) for partition \"%s\"\n", read, next, partition); free(file->data); file->data = NULL; return -1; } SHA_update(&sha_ctx, p, read); file->size += 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)); const uint8_t* sha_so_far = SHA_final(&temp_ctx); if (ParseSha1(sha1sum[index[i]], parsed_sha) != 0) { fprintf(stderr, "failed to parse sha1 %s in %s\n", sha1sum[index[i]], filename); free(file->data); file->data = NULL; return -1; } if (memcmp(sha_so_far, parsed_sha, SHA_DIGEST_SIZE) == 0) { // we have a match. stop reading the partition; we'll return // the data we've read so far. printf("mtd read matched size %d sha %s\n", size[index[i]], sha1sum[index[i]]); break; } p += read; } mtd_read_close(ctx); if (i == pairs) { // Ran off the end of the list of (size,sha1) pairs without // finding a match. fprintf(stderr, "contents of MTD partition \"%s\" didn't match %s\n", partition, filename); free(file->data); file->data = NULL; return -1; } const uint8_t* sha_final = SHA_final(&sha_ctx); for (i = 0; i < SHA_DIGEST_SIZE; ++i) { file->sha1[i] = sha_final[i]; } // Fake some stat() info. file->st.st_mode = 0644; file->st.st_uid = 0; file->st.st_gid = 0; free(copy); free(index); free(size); free(sha1sum); return 0; }
int main(int argc, char **argv) { boot_img_hdr hdr; char *kernel_fn = NULL; void *kernel_data = NULL; char *ramdisk_fn = NULL; void *ramdisk_data = NULL; char *second_fn = NULL; void *second_data = NULL; char *cmdline = ""; char *bootimg = NULL; char *board = ""; char *dt_fn = NULL; void *dt_data = NULL; uint32_t pagesize = 2048; int fd; SHA_CTX ctx; const uint8_t* sha; uint32_t base = 0x10000000U; uint32_t kernel_offset = 0xFE208100; uint32_t ramdisk_offset = 0x00200100; uint32_t second_offset = 0xFF100100; uint32_t tags_offset = 0x00000100U; size_t cmdlen; argc--; argv++; memset(&hdr, 0, sizeof(hdr)); bool get_id = false; while(argc > 0){ char *arg = argv[0]; if (!strcmp(arg, "--id")) { get_id = true; argc -= 1; argv += 1; } else if(argc >= 2) { char *val = argv[1]; argc -= 2; argv += 2; if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) { bootimg = val; } else if(!strcmp(arg, "--kernel")) { kernel_fn = val; } else if(!strcmp(arg, "--ramdisk")) { ramdisk_fn = val; } else if(!strcmp(arg, "--second")) { second_fn = val; } else if(!strcmp(arg, "--cmdline")) { cmdline = val; } else if(!strcmp(arg, "--base")) { base = strtoul(val, 0, 16); } else if(!strcmp(arg, "--kernel_offset")) { kernel_offset = strtoul(val, 0, 16); } else if(!strcmp(arg, "--ramdisk_offset")) { ramdisk_offset = strtoul(val, 0, 16); } else if(!strcmp(arg, "--second_offset")) { second_offset = strtoul(val, 0, 16); } else if(!strcmp(arg, "--tags_offset")) { tags_offset = strtoul(val, 0, 16); } else if(!strcmp(arg, "--board")) { board = val; } else if(!strcmp(arg,"--pagesize")) { pagesize = strtoul(val, 0, 10); if ((pagesize != 2048) && (pagesize != 4096) && (pagesize != 8192) && (pagesize != 16384) && (pagesize != 32768) && (pagesize != 65536) && (pagesize != 131072)) { fprintf(stderr,"error: unsupported page size %d\n", pagesize); return -1; } } else if(!strcmp(arg, "--dt")) { dt_fn = val; } else { return usage(); } } else { return usage(); } } hdr.page_size = pagesize; hdr.kernel_addr = base + kernel_offset; hdr.ramdisk_addr = base + ramdisk_offset; hdr.second_addr = base + second_offset; hdr.tags_addr = base + tags_offset; if(bootimg == 0) { fprintf(stderr,"error: no output filename specified\n"); return usage(); } if(kernel_fn == 0) { fprintf(stderr,"error: no kernel image specified\n"); return usage(); } if(ramdisk_fn == 0) { fprintf(stderr,"error: no ramdisk image specified\n"); return usage(); } if(strlen(board) >= BOOT_NAME_SIZE) { fprintf(stderr,"error: board name too large\n"); return usage(); } strcpy((char *) hdr.name, board); memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE); cmdlen = strlen(cmdline); if(cmdlen > (BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE - 2)) { fprintf(stderr,"error: kernel commandline too large\n"); return 1; } /* Even if we need to use the supplemental field, ensure we * are still NULL-terminated */ strncpy((char *)hdr.cmdline, cmdline, BOOT_ARGS_SIZE - 1); hdr.cmdline[BOOT_ARGS_SIZE - 1] = '\0'; if (cmdlen >= (BOOT_ARGS_SIZE - 1)) { cmdline += (BOOT_ARGS_SIZE - 1); strncpy((char *)hdr.extra_cmdline, cmdline, BOOT_EXTRA_ARGS_SIZE); } kernel_data = load_file(kernel_fn, &hdr.kernel_size); if(kernel_data == 0) { fprintf(stderr,"error: could not load kernel '%s'\n", kernel_fn); return 1; } if(!strcmp(ramdisk_fn,"NONE")) { ramdisk_data = 0; hdr.ramdisk_size = 0; } else { ramdisk_data = load_file(ramdisk_fn, &hdr.ramdisk_size); if(ramdisk_data == 0) { fprintf(stderr,"error: could not load ramdisk '%s'\n", ramdisk_fn); return 1; } } if(second_fn) { second_data = load_file(second_fn, &hdr.second_size); if(second_data == 0) { fprintf(stderr,"error: could not load secondstage '%s'\n", second_fn); return 1; } } if(dt_fn) { dt_data = load_file(dt_fn, &hdr.dt_size); if (dt_data == 0) { fprintf(stderr,"error: could not load device tree image '%s'\n", dt_fn); return 1; } } /* put a hash of the contents in the header so boot images can be * differentiated based on their first 2k. */ SHA_init(&ctx); SHA_update(&ctx, kernel_data, hdr.kernel_size); SHA_update(&ctx, &hdr.kernel_size, sizeof(hdr.kernel_size)); SHA_update(&ctx, ramdisk_data, hdr.ramdisk_size); SHA_update(&ctx, &hdr.ramdisk_size, sizeof(hdr.ramdisk_size)); SHA_update(&ctx, second_data, hdr.second_size); SHA_update(&ctx, &hdr.second_size, sizeof(hdr.second_size)); if(dt_data) { SHA_update(&ctx, dt_data, hdr.dt_size); SHA_update(&ctx, &hdr.dt_size, sizeof(hdr.dt_size)); } sha = SHA_final(&ctx); memcpy(hdr.id, sha, SHA_DIGEST_SIZE > sizeof(hdr.id) ? sizeof(hdr.id) : SHA_DIGEST_SIZE); fd = open(bootimg, O_CREAT | O_TRUNC | O_WRONLY, 0644); if(fd < 0) { fprintf(stderr,"error: could not create '%s'\n", bootimg); return 1; } if(write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) goto fail; if(write_padding(fd, pagesize, sizeof(hdr))) goto fail; if(write(fd, kernel_data, hdr.kernel_size) != (ssize_t) hdr.kernel_size) goto fail; if(write_padding(fd, pagesize, hdr.kernel_size)) goto fail; if(write(fd, ramdisk_data, hdr.ramdisk_size) != (ssize_t) hdr.ramdisk_size) goto fail; if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail; if(second_data) { if(write(fd, second_data, hdr.second_size) != (ssize_t) hdr.second_size) goto fail; if(write_padding(fd, pagesize, hdr.second_size)) goto fail; } if(dt_data) { if(write(fd, dt_data, hdr.dt_size) != (ssize_t) hdr.dt_size) goto fail; if(write_padding(fd, pagesize, hdr.dt_size)) goto fail; } if (get_id) { print_id((uint8_t *) hdr.id, sizeof(hdr.id)); } return 0; fail: unlink(bootimg); close(fd); fprintf(stderr,"error: failed writing '%s': %s\n", bootimg, strerror(errno)); return 1; }
int main(int argc, char **argv) { boot_img_hdr hdr; char *kernel_fn = 0; void *kernel_data = 0; char *ramdisk_fn = 0; void *ramdisk_data = 0; char *second_fn = 0; void *second_data = 0; char *cmdline = ""; char *bootimg = 0; char *board = ""; char *dt_fn = 0; void *dt_data = 0; unsigned pagesize = 2048; int fd; SHA_CTX ctx; uint8_t* sha; unsigned base = 0x10000000; unsigned kernel_offset = 0x00008000; unsigned ramdisk_offset = 0x01000000; unsigned second_offset = 0x00f00000; unsigned tags_offset = 0x00000100; argc--; argv++; memset(&hdr, 0, sizeof(hdr)); while(argc > 0){ char *arg = argv[0]; char *val = argv[1]; if(argc < 2) { return usage(); } argc -= 2; argv += 2; if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) { bootimg = val; } else if(!strcmp(arg, "--kernel")) { kernel_fn = val; } else if(!strcmp(arg, "--ramdisk")) { ramdisk_fn = val; } else if(!strcmp(arg, "--second")) { second_fn = val; } else if(!strcmp(arg, "--cmdline")) { cmdline = val; } else if(!strcmp(arg, "--base")) { base = strtoul(val, 0, 16); } else if(!strcmp(arg, "--kernel_offset")) { kernel_offset = strtoul(val, 0, 16); } else if(!strcmp(arg, "--ramdisk_offset")) { ramdisk_offset = strtoul(val, 0, 16); } else if(!strcmp(arg, "--second_offset")) { second_offset = strtoul(val, 0, 16); } else if(!strcmp(arg, "--tags_offset")) { tags_offset = strtoul(val, 0, 16); } else if(!strcmp(arg, "--board")) { board = val; } else if(!strcmp(arg,"--pagesize")) { pagesize = strtoul(val, 0, 10); if ((pagesize != 2048) && (pagesize != 4096) && (pagesize != 8192) && (pagesize != 16384)) { fprintf(stderr,"error: unsupported page size %d\n", pagesize); return -1; } } else if(!strcmp(arg, "--dt")) { dt_fn = val; } else { return usage(); } } hdr.page_size = pagesize; hdr.kernel_addr = base + kernel_offset; hdr.ramdisk_addr = base + ramdisk_offset; hdr.second_addr = base + second_offset; hdr.tags_addr = base + tags_offset; if(bootimg == 0) { fprintf(stderr,"error: no output filename specified\n"); return usage(); } if(kernel_fn == 0) { fprintf(stderr,"error: no kernel image specified\n"); return usage(); } if(ramdisk_fn == 0) { fprintf(stderr,"error: no ramdisk image specified\n"); return usage(); } if(strlen(board) >= BOOT_NAME_SIZE) { fprintf(stderr,"error: board name too large\n"); return usage(); } strcpy(hdr.name, board); memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE); if(strlen(cmdline) > (BOOT_ARGS_SIZE - 1)) { fprintf(stderr,"error: kernel commandline too large\n"); return 1; } strcpy((char*)hdr.cmdline, cmdline); kernel_data = load_file(kernel_fn, &hdr.kernel_size); if(kernel_data == 0) { fprintf(stderr,"error: could not load kernel '%s'\n", kernel_fn); return 1; } if(!strcmp(ramdisk_fn,"NONE")) { ramdisk_data = 0; hdr.ramdisk_size = 0; } else { ramdisk_data = load_file(ramdisk_fn, &hdr.ramdisk_size); if(ramdisk_data == 0) { fprintf(stderr,"error: could not load ramdisk '%s'\n", ramdisk_fn); return 1; } } if(second_fn) { second_data = load_file(second_fn, &hdr.second_size); if(second_data == 0) { fprintf(stderr,"error: could not load secondstage '%s'\n", second_fn); return 1; } } if(dt_fn) { dt_data = load_file(dt_fn, &hdr.dt_size); if (dt_data == 0) { fprintf(stderr,"error: could not load device tree image '%s'\n", dt_fn); return 1; } } /* put a hash of the contents in the header so boot images can be * differentiated based on their first 2k. */ SHA_init(&ctx); SHA_update(&ctx, kernel_data, hdr.kernel_size); SHA_update(&ctx, &hdr.kernel_size, sizeof(hdr.kernel_size)); SHA_update(&ctx, ramdisk_data, hdr.ramdisk_size); SHA_update(&ctx, &hdr.ramdisk_size, sizeof(hdr.ramdisk_size)); SHA_update(&ctx, second_data, hdr.second_size); SHA_update(&ctx, &hdr.second_size, sizeof(hdr.second_size)); if(dt_data) { SHA_update(&ctx, dt_data, hdr.dt_size); SHA_update(&ctx, &hdr.dt_size, sizeof(hdr.dt_size)); } sha = SHA_final(&ctx); memcpy(hdr.id, sha, SHA_DIGEST_SIZE > sizeof(hdr.id) ? sizeof(hdr.id) : SHA_DIGEST_SIZE); fd = open(bootimg, O_CREAT | O_TRUNC | O_WRONLY, 0644); if(fd < 0) { fprintf(stderr,"error: could not create '%s'\n", bootimg); return 1; } if(write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) goto fail; if(write_padding(fd, pagesize, sizeof(hdr))) goto fail; if(write(fd, kernel_data, hdr.kernel_size) != hdr.kernel_size) goto fail; if(write_padding(fd, pagesize, hdr.kernel_size)) goto fail; if(write(fd, ramdisk_data, hdr.ramdisk_size) != hdr.ramdisk_size) goto fail; if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail; if(second_data) { if(write(fd, second_data, hdr.second_size) != hdr.second_size) goto fail; if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail; } if(dt_data) { if(write(fd, dt_data, hdr.dt_size) != hdr.dt_size) goto fail; if(write_padding(fd, pagesize, hdr.dt_size)) goto fail; } return 0; fail: unlink(bootimg); close(fd); fprintf(stderr,"error: failed writing '%s': %s\n", bootimg, strerror(errno)); return 1; }
int pack_main(char *dir, char *bootimg) { char tmp[PATH_MAX]; char *img_info = 0; char *kernel_fn; void *kernel_data; char *ramdisk_fn; void *ramdisk_data = 0; char *second_fn = 0; void *second_data = 0; FILE *flag_fn = 0; unsigned char *flag_data[512]; char *board = ""; char *dt_fn = 0; void *dt_data = 0; int fd; SHA_CTX ctx; const uint8_t *sha; int _BOOTIMG_MTK = 0; memset(&hdr, 0, sizeof(hdr)); char *__now_path = getcwd(NULL, NULL); hdr.kernel_addr = 0x10008000; hdr.ramdisk_addr = 0x11000000; hdr.second_addr = 0x10F00000; hdr.tags_addr = 0x10000100; chdir(dir); repack_ramdisk_main(dir); sprintf(tmp, "%s/%s", __now_path, bootimg); bootimg = tmp; kernel_fn = "zImage"; ramdisk_fn = "ramdisk-new.cpio.gz"; dt_fn = "dt.img"; img_info = "img_info.txt"; if (exist(kernel_fn)) { fprintf(stderr, "找不到:%s\n", kernel_fn); //exit(-1); } if (exist(ramdisk_fn)) { fprintf(stderr, "找不到:%s\n", ramdisk_fn); //exit(-1); } if (exist(dt_fn)) { //fprintf(stderr, "no dt.img\n", dt_fn); dt_fn = 0; } if (exist(img_info)) { fprintf(stderr, "找不到:%s\n", img_info); //exit(-1); } if(!exist(".mtk_flag")){ _BOOTIMG_MTK = 1; } read_img_info(img_info); if(_BOOTIMG_MTK){ cmdline = ""; } hdr.page_size = pagesize; strcpy((char *)hdr.name, board); memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE); if(_BOOTIMG_MTK){ // MTK 需要多写入512字节 char *ram_old = ramdisk_fn; char *ram_new = "ramdisk-new.cpio.gz.revised"; FILE *flag_fn = fopen(".mtk_flag", "rb"); fread(flag_data, 512, 1, flag_fn); FILE *ram_fn = fopen(ram_old, "rb"); fseek(ram_fn, 0, SEEK_END); long ram_size = ftell(ram_fn); fseek(ram_fn, 0, SEEK_SET); unsigned char buf[ram_size]; fread(buf, ram_size, 1, ram_fn); FILE *new_fn = fopen(ram_new, "wb"); fwrite(flag_data, 512, 1, new_fn); fwrite(buf, ram_size, 1, new_fn); fclose(ram_fn); fclose(new_fn); fclose(flag_fn); unlink(ram_old); ramdisk_fn = ram_new; } if (strlen(cmdline) > (BOOT_ARGS_SIZE - 1)) { fprintf(stderr, "error: kernel commandline too large\n"); return 1; } strcpy((char *)hdr.cmdline, cmdline); kernel_data = load_file(kernel_fn, &hdr.kernel_size); if (!strcmp(ramdisk_fn, "NONE")) { ramdisk_data = 0; hdr.ramdisk_size = 0; } else { ramdisk_data = load_file(ramdisk_fn, &hdr.ramdisk_size); } if (second_fn) { second_data = load_file(second_fn, &hdr.second_size); if (second_data == 0) { fprintf(stderr, "error: could not load secondstage '%s'\n", second_fn); return 1; } } if (dt_fn) { dt_data = load_file(dt_fn, &hdr.dt_size); if (dt_data == 0) { fprintf(stderr, "error: could not load device tree image '%s'\n", dt_fn); return 1; } } /* put a hash of the contents in the header so boot images can be differentiated based on their first 2k. */ SHA_init(&ctx); SHA_update(&ctx, kernel_data, (int)hdr.kernel_size); SHA_update(&ctx, &hdr.kernel_size, (int)sizeof(hdr.kernel_size)); SHA_update(&ctx, ramdisk_data, hdr.ramdisk_size); SHA_update(&ctx, &hdr.ramdisk_size, (int)sizeof(hdr.ramdisk_size)); SHA_update(&ctx, second_data, (int)hdr.second_size); SHA_update(&ctx, &hdr.second_size, (int)sizeof(hdr.second_size)); if (dt_data) { SHA_update(&ctx, dt_data, hdr.dt_size); SHA_update(&ctx, &hdr.dt_size, sizeof(hdr.dt_size)); } sha = SHA_final(&ctx); memcpy(hdr.id, sha, SHA_DIGEST_SIZE > sizeof(hdr.id) ? sizeof(hdr.id) : SHA_DIGEST_SIZE); fd = open(bootimg, O_CREAT | O_TRUNC | O_WRONLY, 0777); if (fd < 0) { fprintf(stderr, "无法创建:'%s'\n", bootimg); return 1; } if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) goto fail; if (write_padding(fd, pagesize, sizeof(hdr))) goto fail; if (write(fd, kernel_data, hdr.kernel_size) != (signed)hdr.kernel_size) goto fail; if (write_padding(fd, pagesize, hdr.kernel_size)) goto fail; if (write(fd, ramdisk_data, hdr.ramdisk_size) != (signed)hdr.ramdisk_size) goto fail; if (write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail; if (second_data) { if (write(fd, second_data, hdr.second_size) != (signed)hdr.second_size) goto fail; if (write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail; } if (dt_data) { if (write(fd, dt_data, hdr.dt_size) != hdr.dt_size) goto fail; if (write_padding(fd, pagesize, hdr.dt_size)) goto fail; } return 0; fail: unlink(bootimg); close(fd); fprintf(stderr, "error: failed writing '%s': %s\n", bootimg, strerror(errno)); return 1; }
// Look for an RSA signature embedded in the .ZIP file comment given // the path to the zip. Verify it matches one of the given public // keys. // // Return VERIFY_SUCCESS, VERIFY_FAILURE (if any error is encountered // or no key matches the signature). int verify_file(unsigned char* addr, size_t length) { //ui->SetProgress(0.0); int numKeys; Certificate* pKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys); if (pKeys == NULL) { LOGE("Failed to load keys\n"); return INSTALL_CORRUPT; } LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE); // An archive with a whole-file signature will end in six bytes: // // (2-byte signature start) $ff $ff (2-byte comment size) // // (As far as the ZIP format is concerned, these are part of the // archive comment.) We start by reading this footer, this tells // us how far back from the end we have to start reading to find // the whole comment. #define FOOTER_SIZE 6 if (length < FOOTER_SIZE) { LOGE("not big enough to contain footer\n"); return VERIFY_FAILURE; } unsigned char* footer = addr + length - FOOTER_SIZE; if (footer[2] != 0xff || footer[3] != 0xff) { LOGE("footer is wrong\n"); return VERIFY_FAILURE; } size_t comment_size = footer[4] + (footer[5] << 8); size_t signature_start = footer[0] + (footer[1] << 8); LOGI("comment is %zu bytes; signature %zu bytes from end\n", comment_size, signature_start); if (signature_start <= FOOTER_SIZE) { LOGE("Signature start is in the footer"); return VERIFY_FAILURE; } #define EOCD_HEADER_SIZE 22 // The end-of-central-directory record is 22 bytes plus any // comment length. size_t eocd_size = comment_size + EOCD_HEADER_SIZE; if (length < eocd_size) { LOGE("not big enough to contain EOCD\n"); return VERIFY_FAILURE; } // Determine how much of the file is covered by the signature. // This is everything except the signature data and length, which // includes all of the EOCD except for the comment length field (2 // bytes) and the comment data. size_t signed_len = length - eocd_size + EOCD_HEADER_SIZE - 2; unsigned char* eocd = addr + length - eocd_size; // If this is really is the EOCD record, it will begin with the // magic number $50 $4b $05 $06. if (eocd[0] != 0x50 || eocd[1] != 0x4b || eocd[2] != 0x05 || eocd[3] != 0x06) { LOGE("signature length doesn't match EOCD marker\n"); return VERIFY_FAILURE; } size_t i; for (i = 4; i < eocd_size-3; ++i) { if (eocd[i ] == 0x50 && eocd[i+1] == 0x4b && eocd[i+2] == 0x05 && eocd[i+3] == 0x06) { // if the sequence $50 $4b $05 $06 appears anywhere after // the real one, minzip will find the later (wrong) one, // which could be exploitable. Fail verification if // this sequence occurs anywhere after the real one. LOGE("EOCD marker occurs after start of EOCD\n"); return VERIFY_FAILURE; } } #define BUFFER_SIZE 4096 bool need_sha1 = false; bool need_sha256 = false; for (i = 0; i < numKeys; ++i) { switch (pKeys[i].hash_len) { case SHA_DIGEST_SIZE: need_sha1 = true; break; case SHA256_DIGEST_SIZE: need_sha256 = true; break; } } SHA_CTX sha1_ctx; SHA256_CTX sha256_ctx; SHA_init(&sha1_ctx); SHA256_init(&sha256_ctx); double frac = -1.0; size_t so_far = 0; while (so_far < signed_len) { size_t size = signed_len - so_far; if (size > BUFFER_SIZE) size = BUFFER_SIZE; if (need_sha1) SHA_update(&sha1_ctx, addr + so_far, size); if (need_sha256) SHA256_update(&sha256_ctx, addr + so_far, size); so_far += size; double f = so_far / (double)signed_len; if (f > frac + 0.02 || size == so_far) { //ui->SetProgress(f); frac = f; } } const uint8_t* sha1 = SHA_final(&sha1_ctx); const uint8_t* sha256 = SHA256_final(&sha256_ctx); uint8_t* sig_der = NULL; size_t sig_der_length = 0; size_t signature_size = signature_start - FOOTER_SIZE; if (!read_pkcs7(eocd + eocd_size - signature_start, signature_size, &sig_der, &sig_der_length)) { LOGE("Could not find signature DER block\n"); return VERIFY_FAILURE; } /* * Check to make sure at least one of the keys matches the signature. Since * any key can match, we need to try each before determining a verification * failure has happened. */ for (i = 0; i < numKeys; ++i) { const uint8_t* hash; switch (pKeys[i].hash_len) { case SHA_DIGEST_SIZE: hash = sha1; break; case SHA256_DIGEST_SIZE: hash = sha256; break; default: continue; } // The 6 bytes is the "(signature_start) $ff $ff (comment_size)" that // the signing tool appends after the signature itself. if (pKeys[i].key_type == Certificate::RSA) { if (sig_der_length < RSANUMBYTES) { // "signature" block isn't big enough to contain an RSA block. LOGI("signature is too short for RSA key %zu\n", i); continue; } if (!RSA_verify(pKeys[i].rsa, sig_der, RSANUMBYTES, hash, pKeys[i].hash_len)) { LOGI("failed to verify against RSA key %zu\n", i); continue; } LOGI("whole-file signature verified against RSA key %zu\n", i); free(sig_der); return VERIFY_SUCCESS; } else if (pKeys[i].key_type == Certificate::EC && pKeys[i].hash_len == SHA256_DIGEST_SIZE) { p256_int r, s; if (!dsa_sig_unpack(sig_der, sig_der_length, &r, &s)) { LOGI("Not a DSA signature block for EC key %zu\n", i); continue; } p256_int p256_hash; p256_from_bin(hash, &p256_hash); if (!p256_ecdsa_verify(&(pKeys[i].ec->x), &(pKeys[i].ec->y), &p256_hash, &r, &s)) { LOGI("failed to verify against EC key %zu\n", i); continue; } LOGI("whole-file signature verified against EC key %zu\n", i); free(sig_der); return VERIFY_SUCCESS; } else { LOGI("Unknown key type %d\n", pKeys[i].key_type); } LOGI("i: %i, eocd_size: %i, RSANUMBYTES: %i\n", i, eocd_size, RSANUMBYTES); } free(sig_der); LOGE("failed to verify whole-file signature\n"); return VERIFY_FAILURE; }
static bool SecureRKModeVerifyBootImage(rk_boot_img_hdr *boothdr) { int i; uint32 size; uint8 *dataHash; uint32 rsaResult[8]; uint32 hwDataHash[8]; uint8 *rsahash = (uint8 *)rsaResult; BOOT_HEADER *pkeyHead = (BOOT_HEADER *)g_rsa_key_buf; #if 0 { int k = 0; char *buf = boothdr->id; printf("Boot Image Head: magic = %s, sign tag = 0x%x\n", boothdr->magic, boothdr->signTag); printf("Boot Image Head: hash data:\n"); for (k = 0; k < sizeof(boothdr->id); k++) { printf("%02x", buf[k]); } printf("\n"); printf("kernel addr = 0x%x, size = 0x%x\n", boothdr->kernel_addr, boothdr->kernel_size); printf("ramdisk addr = 0x%x, size = 0x%x\n", boothdr->ramdisk_addr, boothdr->ramdisk_size); printf("second addr = 0x%x, size = 0x%x\n", boothdr->second_addr, boothdr->second_size); } #endif /* verify boot/recovery image */ if (memcmp(boothdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE) != 0) { return false; } if (boothdr->signTag != SECURE_BOOT_SIGN_TAG) { return false; } #if 0 { SHA_CTX ctx; SHA_init(&ctx); /* Android image */ SHA_update(&ctx, (void *)boothdr->kernel_addr, boothdr->kernel_size); SHA_update(&ctx, &boothdr->kernel_size, sizeof(boothdr->kernel_size)); SHA_update(&ctx, (void *)boothdr->ramdisk_addr, boothdr->ramdisk_size); SHA_update(&ctx, &boothdr->ramdisk_size, sizeof(boothdr->ramdisk_size)); SHA_update(&ctx, (void *)boothdr->second_addr, boothdr->second_size); SHA_update(&ctx, &boothdr->second_size, sizeof(boothdr->second_size)); /* rockchip's image add information. */ SHA_update(&ctx, &boothdr->tags_addr, sizeof(boothdr->tags_addr)); SHA_update(&ctx, &boothdr->page_size, sizeof(boothdr->page_size)); SHA_update(&ctx, &boothdr->unused, sizeof(boothdr->unused)); SHA_update(&ctx, &boothdr->name, sizeof(boothdr->name)); SHA_update(&ctx, &boothdr->cmdline, sizeof(boothdr->cmdline)); dataHash = SHA_final(&ctx); int k = 0; char *buf = dataHash; printf("Soft Calc Image hash data:\n"); for (k = 0; k < sizeof(boothdr->id); k++) { printf("%02x", buf[k]); } printf("\n"); } #endif size = boothdr->kernel_size + sizeof(boothdr->kernel_size) \ + boothdr->ramdisk_size + sizeof(boothdr->ramdisk_size) \ + boothdr->second_size + sizeof(boothdr->second_size) \ + sizeof(boothdr->tags_addr) + sizeof(boothdr->page_size) \ + sizeof(boothdr->unused) + sizeof(boothdr->name) + sizeof(boothdr->cmdline); CryptoRSAInit((uint32*)(boothdr->rsaHash), pkeyHead->RSA_N, pkeyHead->RSA_E, pkeyHead->RSA_C); CryptoSHAInit(size, 160); /* Android image. */ CryptoSHAStart((uint32 *)(unsigned long)boothdr->kernel_addr, boothdr->kernel_size); CryptoSHAStart((uint32 *)&boothdr->kernel_size, sizeof(boothdr->kernel_size)); CryptoSHAStart((uint32 *)(unsigned long)boothdr->ramdisk_addr, boothdr->ramdisk_size); CryptoSHAStart((uint32 *)&boothdr->ramdisk_size, sizeof(boothdr->ramdisk_size)); CryptoSHAStart((uint32 *)(unsigned long)boothdr->second_addr, boothdr->second_size); CryptoSHAStart((uint32 *)&boothdr->second_size, sizeof(boothdr->second_size)); /* only rockchip's image add. */ CryptoSHAStart((uint32 *)&boothdr->tags_addr, sizeof(boothdr->tags_addr)); CryptoSHAStart((uint32 *)&boothdr->page_size, sizeof(boothdr->page_size)); CryptoSHAStart((uint32 *)&boothdr->unused, sizeof(boothdr->unused)); CryptoSHAStart((uint32 *)&boothdr->name, sizeof(boothdr->name)); CryptoSHAStart((uint32 *)&boothdr->cmdline, sizeof(boothdr->cmdline)); CryptoSHAEnd(hwDataHash); CryptoRSAEnd(rsaResult); dataHash = (uint8 *)hwDataHash; #if 0 { int k = 0; char *buf = dataHash; printf("Crypto Calc Image hash data:\n"); for (k = 0; k < sizeof(boothdr->id); k++) { printf("%02x", buf[k]); } printf("\n"); } #endif /* check the hash of image */ if (memcmp(boothdr->id, hwDataHash, sizeof(boothdr->id)) != 0) { return false; } /* check the sign of hash */ for (i = 0; i < 20; i++) { if (rsahash[19-i] != dataHash[i]) { return false; } } return true; }
static int LoadPartitionContents(const char* filename, FileContents* file) { std::string copy(filename); std::vector<std::string> pieces = android::base::Split(copy, ":"); if (pieces.size() < 4 || pieces.size() % 2 != 0) { printf("LoadPartitionContents called with bad filename (%s)\n", filename); return -1; } enum PartitionType type; if (pieces[0] == "MTD") { type = MTD; } else if (pieces[0] == "EMMC") { type = EMMC; } else { printf("LoadPartitionContents called with bad filename (%s)\n", filename); return -1; } const char* partition = pieces[1].c_str(); size_t pairs = (pieces.size() - 2) / 2; // # of (size, sha1) pairs in filename std::vector<size_t> index(pairs); std::vector<size_t> size(pairs); std::vector<std::string> 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; } // 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]); } ); 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 = fopen(partition, "rb"); if (dev == NULL) { printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno)); return -1; } } SHA_CTX sha_ctx; SHA_init(&sha_ctx); uint8_t parsed_sha[SHA_DIGEST_SIZE]; // Allocate enough memory to hold the largest size. file->data = reinterpret_cast<unsigned char*>(malloc(size[index[pairs-1]])); char* p = (char*)file->data; file->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; if (next > 0) { switch (type) { case MTD: read = mtd_read_data(ctx, p, next); break; case EMMC: read = fread(p, 1, next, dev); break; } 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; } SHA_update(&sha_ctx, p, read); file->size += 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)); const uint8_t* sha_so_far = SHA_final(&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); free(file->data); file->data = NULL; return -1; } if (memcmp(sha_so_far, parsed_sha, SHA_DIGEST_SIZE) == 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; } p += read; } switch (type) { case MTD: mtd_read_close(ctx); break; case EMMC: fclose(dev); break; } 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; } 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]; } // Fake some stat() info. file->st.st_mode = 0644; file->st.st_uid = 0; file->st.st_gid = 0; 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_SIZE], size_t target_size, const Value* bonus_data) { int retry = 1; SHA_CTX ctx; int output; MemorySinkInfo msi; FileContents* source_to_use; char* outname; int made_copy = 0; // 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'; } else { strcpy(target_fs, target_filename); } 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 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->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); 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, "MTD:", 4) == 0 || 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->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); 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) { // 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; } 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 = 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)); return 1; } sink = FileSink; token = &output; } char* header = patch->data; ssize_t header_bytes_read = patch->size; SHA_init(&ctx); int result; if (header_bytes_read >= 8 && memcmp(header, "BSDIFF40", 8) == 0) { 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) { 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 (fsync(output) != 0) { printf("failed to fsync file \"%s\" (%s)\n", outname, strerror(errno)); result = 1; } if (close(output) != 0) { printf("failed to close file \"%s\" (%s)\n", outname, strerror(errno)); result = 1; } } if (result != 0) { if (retry == 0) { printf("applying patch failed\n"); return result != 0; } else { printf("applying patch failed; retrying\n"); } if (outname != NULL) { unlink(outname); } } else { // succeeded; no need to retry break; } } while (retry-- > 0); const uint8_t* current_target_sha1 = SHA_final(&ctx); if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_SIZE) != 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) { // Copy the temp file to the partition. if (WriteToPartition(msi.buffer, msi.pos, 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)); 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)); return 1; } // Finally, rename the .patch file to replace the target file. if (rename(outname, target_filename) != 0) { printf("rename of .patch to \"%s\" failed: %s\n", target_filename, 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); } // Success! return 0; }