Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1c522df2 authored by Yabin Cui's avatar Yabin Cui
Browse files

applypatch: use vector to store data in FileContents.

Cherry pick this patch because it fixes the problem that
a newed Value is released by free().

Bug: 26906416
Change-Id: Ib53b445cd415a1ed5e95733fbc4073f9ef4dbc43
(cherry picked from commit d6c93afc)
parent 0ba21cff
Loading
Loading
Loading
Loading
+33 −72
Original line number Original line Diff line number Diff line
@@ -56,8 +56,6 @@ static bool mtd_partitions_scanned = false;
//
//
// Return 0 on success.
// Return 0 on success.
int LoadFileContents(const char* filename, FileContents* file) {
int LoadFileContents(const char* filename, FileContents* file) {
    file->data = NULL;

    // A special 'filename' beginning with "MTD:" or "EMMC:" means to
    // A special 'filename' beginning with "MTD:" or "EMMC:" means to
    // load the contents of a partition.
    // load the contents of a partition.
    if (strncmp(filename, "MTD:", 4) == 0 ||
    if (strncmp(filename, "MTD:", 4) == 0 ||
@@ -70,31 +68,22 @@ int LoadFileContents(const char* filename, FileContents* file) {
        return -1;
        return -1;
    }
    }


    file->size = file->st.st_size;
    std::vector<unsigned char> data(file->st.st_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");
    FILE* f = ota_fopen(filename, "rb");
    if (f == NULL) {
    if (f == NULL) {
        printf("failed to open \"%s\": %s\n", filename, strerror(errno));
        printf("failed to open \"%s\": %s\n", filename, strerror(errno));
        return -1;
        return -1;
    }
    }


    size_t bytes_read = ota_fread(data.get(), 1, file->size, f);
    size_t bytes_read = ota_fread(data.data(), 1, data.size(), f);
    if (bytes_read != static_cast<size_t>(file->size)) {
    if (bytes_read != data.size()) {
        printf("short read of \"%s\" (%zu bytes of %zd)\n", filename, bytes_read, file->size);
        printf("short read of \"%s\" (%zu bytes of %zd)\n", filename, bytes_read, data.size());
        fclose(f);
        ota_fclose(f);
        return -1;
        return -1;
    }
    }
    ota_fclose(f);
    ota_fclose(f);
    file->data = data.release();
    file->data = std::move(data);
    SHA1(file->data, file->size, file->sha1);
    SHA1(file->data.data(), file->data.size(), file->sha1);
    return 0;
    return 0;
}
}


@@ -193,17 +182,17 @@ static int LoadPartitionContents(const char* filename, FileContents* file) {
    uint8_t parsed_sha[SHA_DIGEST_LENGTH];
    uint8_t parsed_sha[SHA_DIGEST_LENGTH];


    // Allocate enough memory to hold the largest size.
    // Allocate enough memory to hold the largest size.
    file->data = static_cast<unsigned char*>(malloc(size[index[pairs-1]]));
    std::vector<unsigned char> data(size[index[pairs-1]]);
    char* p = (char*)file->data;
    char* p = reinterpret_cast<char*>(data.data());
    file->size = 0;                // # bytes read so far
    size_t data_size = 0;                // # bytes read so far
    bool found = false;
    bool found = false;


    for (size_t i = 0; i < pairs; ++i) {
    for (size_t i = 0; i < pairs; ++i) {
        // Read enough additional bytes to get us up to the next size. (Again,
        // Read enough additional bytes to get us up to the next size. (Again,
        // we're trying the possibilities in order of increasing size).
        // we're trying the possibilities in order of increasing size).
        size_t next = size[index[i]] - file->size;
        size_t next = size[index[i]] - data_size;
        size_t read = 0;
        if (next > 0) {
        if (next > 0) {
            size_t read = 0;
            switch (type) {
            switch (type) {
                case MTD:
                case MTD:
                    read = mtd_read_data(ctx, p, next);
                    read = mtd_read_data(ctx, p, next);
@@ -216,12 +205,11 @@ static int LoadPartitionContents(const char* filename, FileContents* file) {
            if (next != read) {
            if (next != read) {
                printf("short read (%zu bytes of %zu) for partition \"%s\"\n",
                printf("short read (%zu bytes of %zu) for partition \"%s\"\n",
                       read, next, partition);
                       read, next, partition);
                free(file->data);
                file->data = NULL;
                return -1;
                return -1;
            }
            }
            SHA1_Update(&sha_ctx, p, read);
            SHA1_Update(&sha_ctx, p, read);
            file->size += read;
            data_size += read;
            p += read;
        }
        }


        // Duplicate the SHA context and finalize the duplicate so we can
        // Duplicate the SHA context and finalize the duplicate so we can
@@ -233,8 +221,6 @@ static int LoadPartitionContents(const char* filename, FileContents* file) {


        if (ParseSha1(sha1sum[index[i]].c_str(), parsed_sha) != 0) {
        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);
            printf("failed to parse sha1 %s in %s\n", sha1sum[index[i]].c_str(), filename);
            free(file->data);
            file->data = NULL;
            return -1;
            return -1;
        }
        }


@@ -246,8 +232,6 @@ static int LoadPartitionContents(const char* filename, FileContents* file) {
            found = true;
            found = true;
            break;
            break;
        }
        }

        p += read;
    }
    }


    switch (type) {
    switch (type) {
@@ -264,13 +248,13 @@ static int LoadPartitionContents(const char* filename, FileContents* file) {
    if (!found) {
    if (!found) {
        // Ran off the end of the list of (size,sha1) pairs without finding a match.
        // 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);
        printf("contents of partition \"%s\" didn't match %s\n", partition, filename);
        free(file->data);
        file->data = NULL;
        return -1;
        return -1;
    }
    }


    SHA1_Final(file->sha1, &sha_ctx);
    SHA1_Final(file->sha1, &sha_ctx);


    data.resize(data_size);
    file->data = std::move(data);
    // Fake some stat() info.
    // Fake some stat() info.
    file->st.st_mode = 0644;
    file->st.st_mode = 0644;
    file->st.st_uid = 0;
    file->st.st_uid = 0;
@@ -289,10 +273,10 @@ int SaveFileContents(const char* filename, const FileContents* file) {
        return -1;
        return -1;
    }
    }


    ssize_t bytes_written = FileSink(file->data, file->size, &fd);
    ssize_t bytes_written = FileSink(file->data.data(), file->data.size(), &fd);
    if (bytes_written != file->size) {
    if (bytes_written != static_cast<ssize_t>(file->data.size())) {
        printf("short write of \"%s\" (%zd bytes of %zd) (%s)\n",
        printf("short write of \"%s\" (%zd bytes of %zu) (%s)\n",
               filename, bytes_written, file->size, strerror(errno));
               filename, bytes_written, file->data.size(), strerror(errno));
        ota_close(fd);
        ota_close(fd);
        return -1;
        return -1;
    }
    }
@@ -543,7 +527,6 @@ int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str,
int applypatch_check(const char* filename, int num_patches,
int applypatch_check(const char* filename, int num_patches,
                     char** const patch_sha1_str) {
                     char** const patch_sha1_str) {
    FileContents file;
    FileContents file;
    file.data = NULL;


    // It's okay to specify no sha1s; the check will pass if the
    // It's okay to specify no sha1s; the check will pass if the
    // LoadFileContents is successful.  (Useful for reading
    // LoadFileContents is successful.  (Useful for reading
@@ -555,9 +538,6 @@ int applypatch_check(const char* filename, int num_patches,
        printf("file \"%s\" doesn't have any of expected "
        printf("file \"%s\" doesn't have any of expected "
               "sha1 sums; checking cache\n", filename);
               "sha1 sums; checking cache\n", filename);


        free(file.data);
        file.data = NULL;

        // If the source file is missing or corrupted, it might be because
        // If the source file is missing or corrupted, it might be because
        // we were killed in the middle of patching it.  A copy of it
        // we were killed in the middle of patching it.  A copy of it
        // should have been made in CACHE_TEMP_SOURCE.  If that file
        // should have been made in CACHE_TEMP_SOURCE.  If that file
@@ -571,12 +551,9 @@ int applypatch_check(const char* filename, int num_patches,


        if (FindMatchingPatch(file.sha1, patch_sha1_str, num_patches) < 0) {
        if (FindMatchingPatch(file.sha1, patch_sha1_str, num_patches) < 0) {
            printf("cache bits don't match any sha1 for \"%s\"\n", filename);
            printf("cache bits don't match any sha1 for \"%s\"\n", filename);
            free(file.data);
            return 1;
            return 1;
        }
        }
    }
    }

    free(file.data);
    return 0;
    return 0;
}
}


@@ -674,8 +651,6 @@ int applypatch(const char* source_filename,


    FileContents copy_file;
    FileContents copy_file;
    FileContents source_file;
    FileContents source_file;
    copy_file.data = NULL;
    source_file.data = NULL;
    const Value* source_patch_value = NULL;
    const Value* source_patch_value = NULL;
    const Value* copy_patch_value = NULL;
    const Value* copy_patch_value = NULL;


@@ -685,22 +660,20 @@ int applypatch(const char* source_filename,
            // The early-exit case:  the patch was already applied, this file
            // The early-exit case:  the patch was already applied, this file
            // has the desired hash, nothing for us to do.
            // has the desired hash, nothing for us to do.
            printf("already %s\n", short_sha1(target_sha1).c_str());
            printf("already %s\n", short_sha1(target_sha1).c_str());
            free(source_file.data);
            return 0;
            return 0;
        }
        }
    }
    }


    if (source_file.data == NULL ||
    if (source_file.data.empty() ||
        (target_filename != source_filename &&
        (target_filename != source_filename &&
         strcmp(target_filename, source_filename) != 0)) {
         strcmp(target_filename, source_filename) != 0)) {
        // Need to load the source file:  either we failed to load the
        // 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.
        // target file, or we did but it's different from the source file.
        free(source_file.data);
        source_file.data.clear();
        source_file.data = NULL;
        LoadFileContents(source_filename, &source_file);
        LoadFileContents(source_filename, &source_file);
    }
    }


    if (source_file.data != NULL) {
    if (!source_file.data.empty()) {
        int to_use = FindMatchingPatch(source_file.sha1, patch_sha1_str, num_patches);
        int to_use = FindMatchingPatch(source_file.sha1, patch_sha1_str, num_patches);
        if (to_use >= 0) {
        if (to_use >= 0) {
            source_patch_value = patch_data[to_use];
            source_patch_value = patch_data[to_use];
@@ -708,8 +681,7 @@ int applypatch(const char* source_filename,
    }
    }


    if (source_patch_value == NULL) {
    if (source_patch_value == NULL) {
        free(source_file.data);
        source_file.data.clear();
        source_file.data = NULL;
        printf("source file is bad; trying copy\n");
        printf("source file is bad; trying copy\n");


        if (LoadFileContents(CACHE_TEMP_SOURCE, &copy_file) < 0) {
        if (LoadFileContents(CACHE_TEMP_SOURCE, &copy_file) < 0) {
@@ -726,19 +698,14 @@ int applypatch(const char* source_filename,
        if (copy_patch_value == NULL) {
        if (copy_patch_value == NULL) {
            // fail.
            // fail.
            printf("copy file doesn't match source SHA-1s either\n");
            printf("copy file doesn't match source SHA-1s either\n");
            free(copy_file.data);
            return 1;
            return 1;
        }
        }
    }
    }


    int result = GenerateTarget(&source_file, source_patch_value,
    return GenerateTarget(&source_file, source_patch_value,
                          &copy_file, copy_patch_value,
                          &copy_file, copy_patch_value,
                          source_filename, target_filename,
                          source_filename, target_filename,
                          target_sha1, target_size, bonus_data);
                          target_sha1, target_size, bonus_data);
    free(source_file.data);
    free(copy_file.data);

    return result;
}
}


/*
/*
@@ -759,7 +726,6 @@ int applypatch_flash(const char* source_filename, const char* target_filename,
    }
    }


    FileContents source_file;
    FileContents source_file;
    source_file.data = NULL;
    std::string target_str(target_filename);
    std::string target_str(target_filename);


    std::vector<std::string> pieces = android::base::Split(target_str, ":");
    std::vector<std::string> pieces = android::base::Split(target_str, ":");
@@ -777,7 +743,6 @@ int applypatch_flash(const char* source_filename, const char* target_filename,
        // The early-exit case: the image was already applied, this partition
        // The early-exit case: the image was already applied, this partition
        // has the desired hash, nothing for us to do.
        // has the desired hash, nothing for us to do.
        printf("already %s\n", short_sha1(target_sha1).c_str());
        printf("already %s\n", short_sha1(target_sha1).c_str());
        free(source_file.data);
        return 0;
        return 0;
    }
    }


@@ -787,18 +752,14 @@ int applypatch_flash(const char* source_filename, const char* target_filename,
            printf("source \"%s\" doesn't have expected sha1 sum\n", source_filename);
            printf("source \"%s\" doesn't have expected sha1 sum\n", source_filename);
            printf("expected: %s, found: %s\n", short_sha1(target_sha1).c_str(),
            printf("expected: %s, found: %s\n", short_sha1(target_sha1).c_str(),
                    short_sha1(source_file.sha1).c_str());
                    short_sha1(source_file.sha1).c_str());
            free(source_file.data);
            return 1;
            return 1;
        }
        }
    }
    }


    if (WriteToPartition(source_file.data, target_size, target_filename) != 0) {
    if (WriteToPartition(source_file.data.data(), target_size, target_filename) != 0) {
        printf("write of copied data to %s failed\n", target_filename);
        printf("write of copied data to %s failed\n", target_filename);
        free(source_file.data);
        return 1;
        return 1;
    }
    }

    free(source_file.data);
    return 0;
    return 0;
}
}


@@ -867,7 +828,7 @@ static int GenerateTarget(FileContents* source_file,


            // We still write the original source to cache, in case
            // We still write the original source to cache, in case
            // the partition write is interrupted.
            // the partition write is interrupted.
            if (MakeFreeSpaceOnCache(source_file->size) < 0) {
            if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) {
                printf("not enough free space on /cache\n");
                printf("not enough free space on /cache\n");
                return 1;
                return 1;
            }
            }
@@ -908,7 +869,7 @@ static int GenerateTarget(FileContents* source_file,
                    return 1;
                    return 1;
                }
                }


                if (MakeFreeSpaceOnCache(source_file->size) < 0) {
                if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) {
                    printf("not enough free space on /cache\n");
                    printf("not enough free space on /cache\n");
                    return 1;
                    return 1;
                }
                }
@@ -951,10 +912,10 @@ static int GenerateTarget(FileContents* source_file,


        int result;
        int result;
        if (use_bsdiff) {
        if (use_bsdiff) {
            result = ApplyBSDiffPatch(source_to_use->data, source_to_use->size,
            result = ApplyBSDiffPatch(source_to_use->data.data(), source_to_use->data.size(),
                                      patch, 0, sink, token, &ctx);
                                      patch, 0, sink, token, &ctx);
        } else {
        } else {
            result = ApplyImagePatch(source_to_use->data, source_to_use->size,
            result = ApplyImagePatch(source_to_use->data.data(), source_to_use->data.size(),
                                     patch, sink, token, &ctx, bonus_data);
                                     patch, sink, token, &ctx, bonus_data);
        }
        }


+3 −9
Original line number Original line Diff line number Diff line
@@ -24,17 +24,11 @@
#include "openssl/sha.h"
#include "openssl/sha.h"
#include "edify/expr.h"
#include "edify/expr.h"


typedef struct _Patch {
struct FileContents {
  uint8_t sha1[SHA_DIGEST_LENGTH];
  uint8_t sha1[SHA_DIGEST_LENGTH];
  const char* patch_filename;
  std::vector<unsigned char> data;
} Patch;

typedef struct _FileContents {
  uint8_t sha1[SHA_DIGEST_LENGTH];
  unsigned char* data;
  ssize_t size;
  struct stat st;
  struct stat st;
} FileContents;
};


// When there isn't enough room on the target filesystem to hold the
// When there isn't enough room on the target filesystem to hold the
// patched version of the file, we copy the original here and delete
// patched version of the file, we copy the original here and delete
+31 −36
Original line number Original line Diff line number Diff line
@@ -46,40 +46,32 @@ static int SpaceMode(int argc, char** argv) {
    return CacheSizeCheck(bytes);
    return CacheSizeCheck(bytes);
}
}


// Parse arguments (which should be of the form "<sha1>" or
// Parse arguments (which should be of the form "<sha1>:<filename>"
// "<sha1>:<filename>" into the new parallel arrays *sha1s and
// into the new parallel arrays *sha1s and *files.Returns true on
// *patches (loading file contents into the patches).  Returns true on
// success.
// success.
static bool ParsePatchArgs(int argc, char** argv, std::vector<char*>* sha1s,
static bool ParsePatchArgs(int argc, char** argv, std::vector<char*>* sha1s,
                           std::vector<std::unique_ptr<Value, decltype(&FreeValue)>>* patches) {
                           std::vector<FileContents>* files) {
    uint8_t digest[SHA_DIGEST_LENGTH];
    uint8_t digest[SHA_DIGEST_LENGTH];


    for (int i = 0; i < argc; ++i) {
    for (int i = 0; i < argc; ++i) {
        char* colon = strchr(argv[i], ':');
        char* colon = strchr(argv[i], ':');
        if (colon != NULL) {
        if (colon == nullptr) {
            printf("no ':' in patch argument \"%s\"\n", argv[i]);
            return false;
        }
        *colon = '\0';
        *colon = '\0';
        ++colon;
        ++colon;
        }

        if (ParseSha1(argv[i], digest) != 0) {
        if (ParseSha1(argv[i], digest) != 0) {
            printf("failed to parse sha1 \"%s\"\n", argv[i]);
            printf("failed to parse sha1 \"%s\"\n", argv[i]);
            return false;
            return false;
        }
        }


        sha1s->push_back(argv[i]);
        sha1s->push_back(argv[i]);
        if (colon == NULL) {
            patches->emplace_back(nullptr, FreeValue);
        } else {
        FileContents fc;
        FileContents fc;
        if (LoadFileContents(colon, &fc) != 0) {
        if (LoadFileContents(colon, &fc) != 0) {
            return false;
            return false;
        }
        }
            std::unique_ptr<Value, decltype(&FreeValue)> value(new Value, FreeValue);
        files->push_back(std::move(fc));
            value->type = VAL_BLOB;
            value->size = fc.size;
            value->data = reinterpret_cast<char*>(fc.data);
            patches->push_back(std::move(value));
        }
    }
    }
    return true;
    return true;
}
}
@@ -90,17 +82,19 @@ static int FlashMode(const char* src_filename, const char* tgt_filename,
}
}


static int PatchMode(int argc, char** argv) {
static int PatchMode(int argc, char** argv) {
    std::unique_ptr<Value, decltype(&FreeValue)> bonus(nullptr, FreeValue);
    FileContents bonusFc;
    Value bonusValue;
    Value* bonus = nullptr;

    if (argc >= 3 && strcmp(argv[1], "-b") == 0) {
    if (argc >= 3 && strcmp(argv[1], "-b") == 0) {
        FileContents fc;
        if (LoadFileContents(argv[2], &bonusFc) != 0) {
        if (LoadFileContents(argv[2], &fc) != 0) {
            printf("failed to load bonus file %s\n", argv[2]);
            printf("failed to load bonus file %s\n", argv[2]);
            return 1;
            return 1;
        }
        }
        bonus.reset(new Value);
        bonus = &bonusValue;
        bonus->type = VAL_BLOB;
        bonus->type = VAL_BLOB;
        bonus->size = fc.size;
        bonus->size = bonusFc.data.size();
        bonus->data = reinterpret_cast<char*>(fc.data);
        bonus->data = reinterpret_cast<char*>(bonusFc.data.data());
        argc -= 2;
        argc -= 2;
        argv += 2;
        argv += 2;
    }
    }
@@ -118,28 +112,29 @@ static int PatchMode(int argc, char** argv) {


    // If no <src-sha1>:<patch> is provided, it is in flash mode.
    // If no <src-sha1>:<patch> is provided, it is in flash mode.
    if (argc == 5) {
    if (argc == 5) {
        if (bonus != NULL) {
        if (bonus != nullptr) {
            printf("bonus file not supported in flash mode\n");
            printf("bonus file not supported in flash mode\n");
            return 1;
            return 1;
        }
        }
        return FlashMode(argv[1], argv[2], argv[3], target_size);
        return FlashMode(argv[1], argv[2], argv[3], target_size);
    }
    }


    std::vector<char*> sha1s;
    std::vector<char*> sha1s;
    std::vector<std::unique_ptr<Value, decltype(&FreeValue)>> patches;
    std::vector<FileContents> files;
    if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &patches)) {
    if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &files)) {
        printf("failed to parse patch args\n");
        printf("failed to parse patch args\n");
        return 1;
        return 1;
    }
    }

    std::vector<Value> patches(files.size());
    std::vector<Value*> patch_ptrs;
    std::vector<Value*> patch_ptrs(files.size());
    for (const auto& p : patches) {
    for (size_t i = 0; i < files.size(); ++i) {
        patch_ptrs.push_back(p.get());
        patches[i].type = VAL_BLOB;
        patches[i].size = files[i].data.size();
        patches[i].data = reinterpret_cast<char*>(files[i].data.data());
        patch_ptrs[i] = &patches[i];
    }
    }
    return applypatch(argv[1], argv[2], argv[3], target_size,
    return applypatch(argv[1], argv[2], argv[3], target_size,
                      patch_ptrs.size(), sha1s.data(),
                      patch_ptrs.size(), sha1s.data(),
                      patch_ptrs.data(), bonus.get());
                      patch_ptrs.data(), bonus);
}
}


// This program applies binary patches to files in a way that is safe
// This program applies binary patches to files in a way that is safe
+11 −10
Original line number Original line Diff line number Diff line
@@ -1398,21 +1398,22 @@ Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
    char* filename;
    char* filename;
    if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;
    if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;


    Value* v = reinterpret_cast<Value*>(malloc(sizeof(Value)));
    Value* v = static_cast<Value*>(malloc(sizeof(Value)));
    if (v == nullptr) {
        return nullptr;
    }
    v->type = VAL_BLOB;
    v->type = VAL_BLOB;
    v->size = -1;
    v->data = nullptr;


    FileContents fc;
    FileContents fc;
    if (LoadFileContents(filename, &fc) != 0) {
    if (LoadFileContents(filename, &fc) != 0) {
        free(filename);
        v->data = static_cast<char*>(malloc(fc.data.size()));
        v->size = -1;
        if (v->data != nullptr) {
        v->data = NULL;
            memcpy(v->data, fc.data.data(), fc.data.size());
        free(fc.data);
            v->size = fc.data.size();
        return v;
        }
    }
    }

    v->size = fc.size;
    v->data = (char*)fc.data;

    free(filename);
    free(filename);
    return v;
    return v;
}
}