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

Commit 74c7807a authored by David Anderson's avatar David Anderson
Browse files

fastboot: Handle libsparse failures better.

sparse_file_len is not actually infallible; on Windows it's pretty easy
to make it fail by embedding large files in the stream. fastboot didn't
handle this anywhere, leading to bad sparse images when libsparse
runs out of address space.

Bug: 273933042
Bug: 268872725
Test: fastboot flashall on Windows
Change-Id: Ie68aed2f1970e820350d9f97aa89a6c0242229b8
parent f06debcf
Loading
Loading
Loading
Loading
+8 −10
Original line number Original line Diff line number Diff line
@@ -988,7 +988,7 @@ std::vector<SparsePtr> resparse_file(sparse_file* s, int64_t max_size) {
    }
    }


    const int files = sparse_file_resparse(s, max_size, nullptr, 0);
    const int files = sparse_file_resparse(s, max_size, nullptr, 0);
    if (files < 0) die("Failed to resparse");
    if (files < 0) die("Failed to compute resparse boundaries");


    auto temp = std::make_unique<sparse_file*[]>(files);
    auto temp = std::make_unique<sparse_file*[]>(files);
    const int rv = sparse_file_resparse(s, max_size, temp.get(), files);
    const int rv = sparse_file_resparse(s, max_size, temp.get(), files);
@@ -1057,6 +1057,10 @@ static bool load_buf_fd(unique_fd fd, struct fastboot_buffer* buf) {


    if (sparse_file* s = sparse_file_import(fd.get(), false, false)) {
    if (sparse_file* s = sparse_file_import(fd.get(), false, false)) {
        buf->image_size = sparse_file_len(s, false, false);
        buf->image_size = sparse_file_len(s, false, false);
        if (buf->image_size < 0) {
            LOG(ERROR) << "Could not compute length of sparse file";
            return false;
        }
        sparse_file_destroy(s);
        sparse_file_destroy(s);
    } else {
    } else {
        buf->image_size = sz;
        buf->image_size = sz;
@@ -1166,15 +1170,6 @@ bool is_logical(const std::string& partition) {
    return fb->GetVar("is-logical:" + partition, &value) == fastboot::SUCCESS && value == "yes";
    return fb->GetVar("is-logical:" + partition, &value) == fastboot::SUCCESS && value == "yes";
}
}


static std::string fb_fix_numeric_var(std::string var) {
    // Some bootloaders (angler, for example), send spurious leading whitespace.
    var = android::base::Trim(var);
    // Some bootloaders (hammerhead, for example) use implicit hex.
    // This code used to use strtol with base 16.
    if (!android::base::StartsWith(var, "0x")) var = "0x" + var;
    return var;
}

static uint64_t get_partition_size(const std::string& partition) {
static uint64_t get_partition_size(const std::string& partition) {
    std::string partition_size_str;
    std::string partition_size_str;
    if (fb->GetVar("partition-size:" + partition, &partition_size_str) != fastboot::SUCCESS) {
    if (fb->GetVar("partition-size:" + partition, &partition_size_str) != fastboot::SUCCESS) {
@@ -1247,6 +1242,9 @@ void flash_partition_files(const std::string& partition, const std::vector<Spars
    for (size_t i = 0; i < files.size(); i++) {
    for (size_t i = 0; i < files.size(); i++) {
        sparse_file* s = files[i].get();
        sparse_file* s = files[i].get();
        int64_t sz = sparse_file_len(s, true, false);
        int64_t sz = sparse_file_len(s, true, false);
        if (sz < 0) {
            LOG(FATAL) << "Could not compute length of sparse image for " << partition;
        }
        fb->FlashPartition(partition, s, sz, i + 1, files.size());
        fb->FlashPartition(partition, s, sz, i + 1, files.size());
    }
    }
}
}
+19 −5
Original line number Original line Diff line number Diff line
@@ -19,6 +19,8 @@
#include "filesystem.h"
#include "filesystem.h"
#include "super_flash_helper.h"
#include "super_flash_helper.h"


#include <android-base/parseint.h>

using namespace std::string_literals;
using namespace std::string_literals;


FlashTask::FlashTask(const std::string& slot, const std::string& pname)
FlashTask::FlashTask(const std::string& slot, const std::string& pname)
@@ -70,14 +72,18 @@ void RebootTask::Run() {


FlashSuperLayoutTask::FlashSuperLayoutTask(const std::string& super_name,
FlashSuperLayoutTask::FlashSuperLayoutTask(const std::string& super_name,
                                           std::unique_ptr<SuperFlashHelper> helper,
                                           std::unique_ptr<SuperFlashHelper> helper,
                                           SparsePtr sparse_layout)
                                           SparsePtr sparse_layout, uint64_t super_size)
    : super_name_(super_name),
    : super_name_(super_name),
      helper_(std::move(helper)),
      helper_(std::move(helper)),
      sparse_layout_(std::move(sparse_layout)) {}
      sparse_layout_(std::move(sparse_layout)),
      super_size_(super_size) {}


void FlashSuperLayoutTask::Run() {
void FlashSuperLayoutTask::Run() {
    // Use the reported super partition size as the upper limit, rather than
    // sparse_file_len, which (1) can fail and (2) is kind of expensive, since
    // it will map in all of the embedded fds.
    std::vector<SparsePtr> files;
    std::vector<SparsePtr> files;
    if (int limit = get_sparse_limit(sparse_file_len(sparse_layout_.get(), false, false))) {
    if (int limit = get_sparse_limit(super_size_)) {
        files = resparse_file(sparse_layout_.get(), limit);
        files = resparse_file(sparse_layout_.get(), limit);
    } else {
    } else {
        files.emplace_back(std::move(sparse_layout_));
        files.emplace_back(std::move(sparse_layout_));
@@ -111,12 +117,19 @@ std::unique_ptr<FlashSuperLayoutTask> FlashSuperLayoutTask::Initialize(
    if (fp->fb->GetVar("super-partition-name", &super_name) != fastboot::SUCCESS) {
    if (fp->fb->GetVar("super-partition-name", &super_name) != fastboot::SUCCESS) {
        super_name = "super";
        super_name = "super";
    }
    }
    std::string partition_size_str;


    uint64_t partition_size;
    std::string partition_size_str;
    if (fp->fb->GetVar("partition-size:" + super_name, &partition_size_str) != fastboot::SUCCESS) {
    if (fp->fb->GetVar("partition-size:" + super_name, &partition_size_str) != fastboot::SUCCESS) {
        LOG(VERBOSE) << "Cannot optimize super flashing: could not determine super partition";
        LOG(VERBOSE) << "Cannot optimize super flashing: could not determine super partition";
        return nullptr;
        return nullptr;
    }
    }
    partition_size_str = fb_fix_numeric_var(partition_size_str);
    if (!android::base::ParseUint(partition_size_str, &partition_size)) {
        LOG(VERBOSE) << "Could not parse " << super_name << " size: " << partition_size_str;
        return nullptr;
    }

    std::unique_ptr<SuperFlashHelper> helper = std::make_unique<SuperFlashHelper>(*fp->source);
    std::unique_ptr<SuperFlashHelper> helper = std::make_unique<SuperFlashHelper>(*fp->source);
    if (!helper->Open(fd)) {
    if (!helper->Open(fd)) {
        return nullptr;
        return nullptr;
@@ -140,7 +153,8 @@ std::unique_ptr<FlashSuperLayoutTask> FlashSuperLayoutTask::Initialize(
    };
    };
    os_images.erase(std::remove_if(os_images.begin(), os_images.end(), remove_if_callback),
    os_images.erase(std::remove_if(os_images.begin(), os_images.end(), remove_if_callback),
                    os_images.end());
                    os_images.end());
    return std::make_unique<FlashSuperLayoutTask>(super_name, std::move(helper), std::move(s));
    return std::make_unique<FlashSuperLayoutTask>(super_name, std::move(helper), std::move(s),
                                                  partition_size);
}
}


UpdateSuperTask::UpdateSuperTask(FlashingPlan* fp) : fp_(fp) {}
UpdateSuperTask::UpdateSuperTask(FlashingPlan* fp) : fp_(fp) {}
+2 −1
Original line number Original line Diff line number Diff line
@@ -57,7 +57,7 @@ class RebootTask : public Task {
class FlashSuperLayoutTask : public Task {
class FlashSuperLayoutTask : public Task {
  public:
  public:
    FlashSuperLayoutTask(const std::string& super_name, std::unique_ptr<SuperFlashHelper> helper,
    FlashSuperLayoutTask(const std::string& super_name, std::unique_ptr<SuperFlashHelper> helper,
                         SparsePtr sparse_layout);
                         SparsePtr sparse_layout, uint64_t super_size);
    static std::unique_ptr<FlashSuperLayoutTask> Initialize(FlashingPlan* fp,
    static std::unique_ptr<FlashSuperLayoutTask> Initialize(FlashingPlan* fp,
                                                            std::vector<ImageEntry>& os_images);
                                                            std::vector<ImageEntry>& os_images);
    using ImageEntry = std::pair<const Image*, std::string>;
    using ImageEntry = std::pair<const Image*, std::string>;
@@ -67,6 +67,7 @@ class FlashSuperLayoutTask : public Task {
    const std::string super_name_;
    const std::string super_name_;
    std::unique_ptr<SuperFlashHelper> helper_;
    std::unique_ptr<SuperFlashHelper> helper_;
    SparsePtr sparse_layout_;
    SparsePtr sparse_layout_;
    uint64_t super_size_;
};
};


class UpdateSuperTask : public Task {
class UpdateSuperTask : public Task {
+12 −0
Original line number Original line Diff line number Diff line
@@ -33,6 +33,9 @@
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/time.h>


#include <android-base/parseint.h>
#include <android-base/strings.h>

#include "util.h"
#include "util.h"


using android::base::borrowed_fd;
using android::base::borrowed_fd;
@@ -106,3 +109,12 @@ int64_t get_file_size(borrowed_fd fd) {
    }
    }
    return sb.st_size;
    return sb.st_size;
}
}

std::string fb_fix_numeric_var(std::string var) {
    // Some bootloaders (angler, for example), send spurious leading whitespace.
    var = android::base::Trim(var);
    // Some bootloaders (hammerhead, for example) use implicit hex.
    // This code used to use strtol with base 16.
    if (!android::base::StartsWith(var, "0x")) var = "0x" + var;
    return var;
}
+1 −0
Original line number Original line Diff line number Diff line
@@ -30,6 +30,7 @@ bool should_flash_in_userspace(const android::fs_mgr::LpMetadata& metadata,
                               const std::string& partition_name);
                               const std::string& partition_name);
bool is_sparse_file(android::base::borrowed_fd fd);
bool is_sparse_file(android::base::borrowed_fd fd);
int64_t get_file_size(android::base::borrowed_fd fd);
int64_t get_file_size(android::base::borrowed_fd fd);
std::string fb_fix_numeric_var(std::string var);


class ImageSource {
class ImageSource {
  public:
  public: