Loading fastboot/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -430,6 +430,7 @@ cc_test_host { ], data: [ ":fastboot_test_dtb", ":fastboot_test_dtb_replace", ":fastboot_test_bootconfig", ":fastboot_test_vendor_ramdisk_none", ":fastboot_test_vendor_ramdisk_platform", Loading fastboot/fastboot.cpp +25 −1 Original line number Diff line number Diff line Loading @@ -552,6 +552,12 @@ static int show_help() { " Secondary images may be flashed to inactive slot.\n" " flash PARTITION [FILENAME] Flash given partition, using the image from\n" " $ANDROID_PRODUCT_OUT if no filename is given.\n" " flash vendor_boot:RAMDISK [FILENAME]\n" " Flash vendor_boot ramdisk, fetching the existing\n" " vendor_boot image and repackaging it with the new\n" " ramdisk.\n" " --dtb DTB If set with flash vendor_boot:RAMDISK, then\n" " update the vendor_boot image with provided DTB.\n" "\n" "basics:\n" " devices [-l] List devices in bootloader (-l: with device paths).\n" Loading Loading @@ -1020,6 +1026,8 @@ static uint64_t get_uint_var(const char* var_name, fastboot::IFastBootDriver* fb } int64_t get_sparse_limit(int64_t size, const FlashingPlan* fp) { if (!fp) return 0; int64_t limit = int64_t(fp->sparse_limit); if (limit == 0) { // Unlimited, so see what the target device's limit is. Loading Loading @@ -1465,6 +1473,7 @@ static void do_fetch(const std::string& partition, const std::string& slot_overr static std::string repack_ramdisk(const char* pname, struct fastboot_buffer* buf, fastboot::IFastBootDriver* fb) { std::string_view pname_sv{pname}; struct fastboot_buffer dtb_buf = {.sz = 0, .fd = unique_fd(-1)}; if (!android::base::StartsWith(pname_sv, "vendor_boot:") && !android::base::StartsWith(pname_sv, "vendor_boot_a:") && Loading @@ -1480,10 +1489,25 @@ static std::string repack_ramdisk(const char* pname, struct fastboot_buffer* buf std::string partition(pname_sv.substr(0, pname_sv.find(':'))); std::string ramdisk(pname_sv.substr(pname_sv.find(':') + 1)); if (!g_dtb_path.empty()) { if (!load_buf(g_dtb_path.c_str(), &dtb_buf, nullptr)) { die("cannot load '%s': %s", g_dtb_path.c_str(), strerror(errno)); } if (dtb_buf.type != FB_BUFFER_FD) { die("Flashing sparse vendor ramdisk image with dtb is not supported."); } if (dtb_buf.sz <= 0) { die("repack_ramdisk() sees invalid dtb size: %" PRId64, buf->sz); } verbose("Updating DTB with %s", pname_sv.data()); } unique_fd vendor_boot(make_temporary_fd("vendor boot repack")); uint64_t vendor_boot_size = fetch_partition(partition, vendor_boot, fb); auto repack_res = replace_vendor_ramdisk(vendor_boot, vendor_boot_size, ramdisk, buf->fd, static_cast<uint64_t>(buf->sz)); static_cast<uint64_t>(buf->sz), dtb_buf.fd, static_cast<uint64_t>(dtb_buf.sz)); if (!repack_res.ok()) { die("%s", repack_res.error().message().c_str()); } Loading fastboot/fuzzer/fastboot_fuzzer.cpp +3 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ * */ #include <android-base/file.h> #include <android-base/unique_fd.h> #include "fastboot.h" #include "socket.h" #include "socket_mock_fuzz.h" Loading @@ -25,6 +26,7 @@ #include <fuzzer/FuzzedDataProvider.h> using namespace std; using android::base::unique_fd; const size_t kYearMin = 2000; const size_t kYearMax = 2127; Loading Loading @@ -255,7 +257,7 @@ void FastbootFuzzer::InvokeVendorBootImgUtils(const uint8_t* data, size_t size) uint64_t ramdisk_size = fdp_->ConsumeBool() ? content_ramdisk_fd.size() : fdp_->ConsumeIntegral<uint64_t>(); (void)replace_vendor_ramdisk(vendor_boot_fd, vendor_boot_size, ramdisk_name, ramdisk_fd, ramdisk_size); ramdisk_size, unique_fd(-1), 0); close(vendor_boot_fd); close(ramdisk_fd); } Loading fastboot/testdata/Android.bp +8 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,14 @@ genrule { cmd: "$(location fastboot_gen_rand) --seed dtb --length 1024 > $(out)", } // Fake dtb image for replacement. genrule { name: "fastboot_test_dtb_replace", defaults: ["fastboot_test_data_gen_defaults"], out: ["dtb_replace.img"], cmd: "$(location fastboot_gen_rand) --seed dtb --length 2048 > $(out)", } // Fake bootconfig image. genrule { name: "fastboot_test_bootconfig", Loading fastboot/vendor_boot_img_utils.cpp +44 −15 Original line number Diff line number Diff line Loading @@ -209,7 +209,8 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { // Replace the vendor ramdisk as a whole. [[nodiscard]] Result<std::string> replace_default_vendor_ramdisk(const std::string& vendor_boot, const std::string& new_ramdisk) { const std::string& new_ramdisk, const std::string& new_dtb) { if (auto res = check_vendor_boot_hdr(vendor_boot, 3); !res.ok()) return res.error(); auto hdr = reinterpret_cast<const vendor_boot_img_hdr_v3*>(vendor_boot.data()); auto hdr_size = get_vendor_boot_header_size(hdr); Loading Loading @@ -244,8 +245,19 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { return res.error(); if (auto res = updater.CheckOffset(o + p, o + new_p); !res.ok()) return res.error(); // Copy DTB (Q bytes). // Copy DTB (Q bytes). Replace if a new one was provided. new_hdr->dtb_size = !new_dtb.empty() ? new_dtb.size() : hdr->dtb_size; const uint32_t new_q = round_up(new_hdr->dtb_size, new_hdr->page_size); if (new_dtb.empty()) { if (auto res = updater.Copy(q); !res.ok()) return res.error(); } else { if (auto res = updater.Replace(hdr->dtb_size, new_dtb); !res.ok()) return res.error(); if (auto res = updater.Skip(q - hdr->dtb_size, new_q - new_hdr->dtb_size); !res.ok()) return res.error(); } if (auto res = updater.CheckOffset(o + p + q, o + new_p + new_q); !res.ok()) { return res.error(); } if (new_hdr->header_version >= 4) { auto hdr_v4 = static_cast<const vendor_boot_img_hdr_v4*>(hdr); Loading @@ -256,7 +268,7 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { auto new_hdr_v4 = static_cast<const vendor_boot_img_hdr_v4*>(new_hdr); auto new_r = round_up(new_hdr_v4->vendor_ramdisk_table_size, new_hdr->page_size); if (auto res = updater.Skip(r, new_r); !res.ok()) return res.error(); if (auto res = updater.CheckOffset(o + p + q + r, o + new_p + q + new_r); !res.ok()) if (auto res = updater.CheckOffset(o + p + q + r, o + new_p + new_q + new_r); !res.ok()) return res.error(); // Replace table with single entry representing the full ramdisk. Loading Loading @@ -303,7 +315,8 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { // replace it with the content of |new_ramdisk|. [[nodiscard]] Result<std::string> replace_vendor_ramdisk_fragment(const std::string& ramdisk_name, const std::string& vendor_boot, const std::string& new_ramdisk) { const std::string& new_ramdisk, const std::string& new_dtb) { if (auto res = check_vendor_boot_hdr(vendor_boot, 4); !res.ok()) return res.error(); auto hdr = reinterpret_cast<const vendor_boot_img_hdr_v4*>(vendor_boot.data()); auto hdr_size = get_vendor_boot_header_size(hdr); Loading Loading @@ -368,8 +381,19 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { return res.error(); if (auto res = updater.CheckOffset(o + p, o + new_p); !res.ok()) return res.error(); // Copy DTB (Q bytes). // Copy DTB (Q bytes). Replace if a new one was provided. new_hdr->dtb_size = !new_dtb.empty() ? new_dtb.size() : hdr->dtb_size; const uint32_t new_q = round_up(new_hdr->dtb_size, new_hdr->page_size); if (new_dtb.empty()) { if (auto res = updater.Copy(q); !res.ok()) return res.error(); } else { if (auto res = updater.Replace(hdr->dtb_size, new_dtb); !res.ok()) return res.error(); if (auto res = updater.Skip(q - hdr->dtb_size, new_q - new_hdr->dtb_size); !res.ok()) return res.error(); } if (auto res = updater.CheckOffset(o + p + q, o + new_p + new_q); !res.ok()) { return res.error(); } // Copy table, but with corresponding entries modified, including: // - ramdisk_size of the entry replaced Loading @@ -392,7 +416,7 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { hdr->vendor_ramdisk_table_entry_size); !res.ok()) return res.error(); if (auto res = updater.CheckOffset(o + p + q + r, o + new_p + q + r); !res.ok()) if (auto res = updater.CheckOffset(o + p + q + r, o + new_p + new_q + r); !res.ok()) return res.error(); // Copy bootconfig (S bytes). Loading @@ -404,11 +428,11 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { } // namespace [[nodiscard]] Result<void> replace_vendor_ramdisk(android::base::borrowed_fd vendor_boot_fd, uint64_t vendor_boot_size, const std::string& ramdisk_name, android::base::borrowed_fd new_ramdisk_fd, uint64_t new_ramdisk_size) { [[nodiscard]] Result<void> replace_vendor_ramdisk( android::base::borrowed_fd vendor_boot_fd, uint64_t vendor_boot_size, const std::string& ramdisk_name, android::base::borrowed_fd new_ramdisk_fd, uint64_t new_ramdisk_size, android::base::borrowed_fd new_dtb_fd, uint64_t new_dtb_size) { Result<std::string> new_dtb = {""}; if (new_ramdisk_size > std::numeric_limits<uint32_t>::max()) { return Errorf("New vendor ramdisk is too big"); } Loading @@ -417,12 +441,17 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { if (!vendor_boot.ok()) return vendor_boot.error(); auto new_ramdisk = load_file(new_ramdisk_fd, new_ramdisk_size, "new vendor ramdisk"); if (!new_ramdisk.ok()) return new_ramdisk.error(); if (new_dtb_size > 0 && new_dtb_fd >= 0) { new_dtb = load_file(new_dtb_fd, new_dtb_size, "new dtb"); if (!new_dtb.ok()) return new_dtb.error(); } Result<std::string> new_vendor_boot; if (ramdisk_name == "default") { new_vendor_boot = replace_default_vendor_ramdisk(*vendor_boot, *new_ramdisk); new_vendor_boot = replace_default_vendor_ramdisk(*vendor_boot, *new_ramdisk, *new_dtb); } else { new_vendor_boot = replace_vendor_ramdisk_fragment(ramdisk_name, *vendor_boot, *new_ramdisk); new_vendor_boot = replace_vendor_ramdisk_fragment(ramdisk_name, *vendor_boot, *new_ramdisk, *new_dtb); } if (!new_vendor_boot.ok()) return new_vendor_boot.error(); if (auto res = store_file(vendor_boot_fd, *new_vendor_boot, "new vendor boot image"); !res.ok()) Loading Loading
fastboot/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -430,6 +430,7 @@ cc_test_host { ], data: [ ":fastboot_test_dtb", ":fastboot_test_dtb_replace", ":fastboot_test_bootconfig", ":fastboot_test_vendor_ramdisk_none", ":fastboot_test_vendor_ramdisk_platform", Loading
fastboot/fastboot.cpp +25 −1 Original line number Diff line number Diff line Loading @@ -552,6 +552,12 @@ static int show_help() { " Secondary images may be flashed to inactive slot.\n" " flash PARTITION [FILENAME] Flash given partition, using the image from\n" " $ANDROID_PRODUCT_OUT if no filename is given.\n" " flash vendor_boot:RAMDISK [FILENAME]\n" " Flash vendor_boot ramdisk, fetching the existing\n" " vendor_boot image and repackaging it with the new\n" " ramdisk.\n" " --dtb DTB If set with flash vendor_boot:RAMDISK, then\n" " update the vendor_boot image with provided DTB.\n" "\n" "basics:\n" " devices [-l] List devices in bootloader (-l: with device paths).\n" Loading Loading @@ -1020,6 +1026,8 @@ static uint64_t get_uint_var(const char* var_name, fastboot::IFastBootDriver* fb } int64_t get_sparse_limit(int64_t size, const FlashingPlan* fp) { if (!fp) return 0; int64_t limit = int64_t(fp->sparse_limit); if (limit == 0) { // Unlimited, so see what the target device's limit is. Loading Loading @@ -1465,6 +1473,7 @@ static void do_fetch(const std::string& partition, const std::string& slot_overr static std::string repack_ramdisk(const char* pname, struct fastboot_buffer* buf, fastboot::IFastBootDriver* fb) { std::string_view pname_sv{pname}; struct fastboot_buffer dtb_buf = {.sz = 0, .fd = unique_fd(-1)}; if (!android::base::StartsWith(pname_sv, "vendor_boot:") && !android::base::StartsWith(pname_sv, "vendor_boot_a:") && Loading @@ -1480,10 +1489,25 @@ static std::string repack_ramdisk(const char* pname, struct fastboot_buffer* buf std::string partition(pname_sv.substr(0, pname_sv.find(':'))); std::string ramdisk(pname_sv.substr(pname_sv.find(':') + 1)); if (!g_dtb_path.empty()) { if (!load_buf(g_dtb_path.c_str(), &dtb_buf, nullptr)) { die("cannot load '%s': %s", g_dtb_path.c_str(), strerror(errno)); } if (dtb_buf.type != FB_BUFFER_FD) { die("Flashing sparse vendor ramdisk image with dtb is not supported."); } if (dtb_buf.sz <= 0) { die("repack_ramdisk() sees invalid dtb size: %" PRId64, buf->sz); } verbose("Updating DTB with %s", pname_sv.data()); } unique_fd vendor_boot(make_temporary_fd("vendor boot repack")); uint64_t vendor_boot_size = fetch_partition(partition, vendor_boot, fb); auto repack_res = replace_vendor_ramdisk(vendor_boot, vendor_boot_size, ramdisk, buf->fd, static_cast<uint64_t>(buf->sz)); static_cast<uint64_t>(buf->sz), dtb_buf.fd, static_cast<uint64_t>(dtb_buf.sz)); if (!repack_res.ok()) { die("%s", repack_res.error().message().c_str()); } Loading
fastboot/fuzzer/fastboot_fuzzer.cpp +3 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ * */ #include <android-base/file.h> #include <android-base/unique_fd.h> #include "fastboot.h" #include "socket.h" #include "socket_mock_fuzz.h" Loading @@ -25,6 +26,7 @@ #include <fuzzer/FuzzedDataProvider.h> using namespace std; using android::base::unique_fd; const size_t kYearMin = 2000; const size_t kYearMax = 2127; Loading Loading @@ -255,7 +257,7 @@ void FastbootFuzzer::InvokeVendorBootImgUtils(const uint8_t* data, size_t size) uint64_t ramdisk_size = fdp_->ConsumeBool() ? content_ramdisk_fd.size() : fdp_->ConsumeIntegral<uint64_t>(); (void)replace_vendor_ramdisk(vendor_boot_fd, vendor_boot_size, ramdisk_name, ramdisk_fd, ramdisk_size); ramdisk_size, unique_fd(-1), 0); close(vendor_boot_fd); close(ramdisk_fd); } Loading
fastboot/testdata/Android.bp +8 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,14 @@ genrule { cmd: "$(location fastboot_gen_rand) --seed dtb --length 1024 > $(out)", } // Fake dtb image for replacement. genrule { name: "fastboot_test_dtb_replace", defaults: ["fastboot_test_data_gen_defaults"], out: ["dtb_replace.img"], cmd: "$(location fastboot_gen_rand) --seed dtb --length 2048 > $(out)", } // Fake bootconfig image. genrule { name: "fastboot_test_bootconfig", Loading
fastboot/vendor_boot_img_utils.cpp +44 −15 Original line number Diff line number Diff line Loading @@ -209,7 +209,8 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { // Replace the vendor ramdisk as a whole. [[nodiscard]] Result<std::string> replace_default_vendor_ramdisk(const std::string& vendor_boot, const std::string& new_ramdisk) { const std::string& new_ramdisk, const std::string& new_dtb) { if (auto res = check_vendor_boot_hdr(vendor_boot, 3); !res.ok()) return res.error(); auto hdr = reinterpret_cast<const vendor_boot_img_hdr_v3*>(vendor_boot.data()); auto hdr_size = get_vendor_boot_header_size(hdr); Loading Loading @@ -244,8 +245,19 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { return res.error(); if (auto res = updater.CheckOffset(o + p, o + new_p); !res.ok()) return res.error(); // Copy DTB (Q bytes). // Copy DTB (Q bytes). Replace if a new one was provided. new_hdr->dtb_size = !new_dtb.empty() ? new_dtb.size() : hdr->dtb_size; const uint32_t new_q = round_up(new_hdr->dtb_size, new_hdr->page_size); if (new_dtb.empty()) { if (auto res = updater.Copy(q); !res.ok()) return res.error(); } else { if (auto res = updater.Replace(hdr->dtb_size, new_dtb); !res.ok()) return res.error(); if (auto res = updater.Skip(q - hdr->dtb_size, new_q - new_hdr->dtb_size); !res.ok()) return res.error(); } if (auto res = updater.CheckOffset(o + p + q, o + new_p + new_q); !res.ok()) { return res.error(); } if (new_hdr->header_version >= 4) { auto hdr_v4 = static_cast<const vendor_boot_img_hdr_v4*>(hdr); Loading @@ -256,7 +268,7 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { auto new_hdr_v4 = static_cast<const vendor_boot_img_hdr_v4*>(new_hdr); auto new_r = round_up(new_hdr_v4->vendor_ramdisk_table_size, new_hdr->page_size); if (auto res = updater.Skip(r, new_r); !res.ok()) return res.error(); if (auto res = updater.CheckOffset(o + p + q + r, o + new_p + q + new_r); !res.ok()) if (auto res = updater.CheckOffset(o + p + q + r, o + new_p + new_q + new_r); !res.ok()) return res.error(); // Replace table with single entry representing the full ramdisk. Loading Loading @@ -303,7 +315,8 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { // replace it with the content of |new_ramdisk|. [[nodiscard]] Result<std::string> replace_vendor_ramdisk_fragment(const std::string& ramdisk_name, const std::string& vendor_boot, const std::string& new_ramdisk) { const std::string& new_ramdisk, const std::string& new_dtb) { if (auto res = check_vendor_boot_hdr(vendor_boot, 4); !res.ok()) return res.error(); auto hdr = reinterpret_cast<const vendor_boot_img_hdr_v4*>(vendor_boot.data()); auto hdr_size = get_vendor_boot_header_size(hdr); Loading Loading @@ -368,8 +381,19 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { return res.error(); if (auto res = updater.CheckOffset(o + p, o + new_p); !res.ok()) return res.error(); // Copy DTB (Q bytes). // Copy DTB (Q bytes). Replace if a new one was provided. new_hdr->dtb_size = !new_dtb.empty() ? new_dtb.size() : hdr->dtb_size; const uint32_t new_q = round_up(new_hdr->dtb_size, new_hdr->page_size); if (new_dtb.empty()) { if (auto res = updater.Copy(q); !res.ok()) return res.error(); } else { if (auto res = updater.Replace(hdr->dtb_size, new_dtb); !res.ok()) return res.error(); if (auto res = updater.Skip(q - hdr->dtb_size, new_q - new_hdr->dtb_size); !res.ok()) return res.error(); } if (auto res = updater.CheckOffset(o + p + q, o + new_p + new_q); !res.ok()) { return res.error(); } // Copy table, but with corresponding entries modified, including: // - ramdisk_size of the entry replaced Loading @@ -392,7 +416,7 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { hdr->vendor_ramdisk_table_entry_size); !res.ok()) return res.error(); if (auto res = updater.CheckOffset(o + p + q + r, o + new_p + q + r); !res.ok()) if (auto res = updater.CheckOffset(o + p + q + r, o + new_p + new_q + r); !res.ok()) return res.error(); // Copy bootconfig (S bytes). Loading @@ -404,11 +428,11 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { } // namespace [[nodiscard]] Result<void> replace_vendor_ramdisk(android::base::borrowed_fd vendor_boot_fd, uint64_t vendor_boot_size, const std::string& ramdisk_name, android::base::borrowed_fd new_ramdisk_fd, uint64_t new_ramdisk_size) { [[nodiscard]] Result<void> replace_vendor_ramdisk( android::base::borrowed_fd vendor_boot_fd, uint64_t vendor_boot_size, const std::string& ramdisk_name, android::base::borrowed_fd new_ramdisk_fd, uint64_t new_ramdisk_size, android::base::borrowed_fd new_dtb_fd, uint64_t new_dtb_size) { Result<std::string> new_dtb = {""}; if (new_ramdisk_size > std::numeric_limits<uint32_t>::max()) { return Errorf("New vendor ramdisk is too big"); } Loading @@ -417,12 +441,17 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { if (!vendor_boot.ok()) return vendor_boot.error(); auto new_ramdisk = load_file(new_ramdisk_fd, new_ramdisk_size, "new vendor ramdisk"); if (!new_ramdisk.ok()) return new_ramdisk.error(); if (new_dtb_size > 0 && new_dtb_fd >= 0) { new_dtb = load_file(new_dtb_fd, new_dtb_size, "new dtb"); if (!new_dtb.ok()) return new_dtb.error(); } Result<std::string> new_vendor_boot; if (ramdisk_name == "default") { new_vendor_boot = replace_default_vendor_ramdisk(*vendor_boot, *new_ramdisk); new_vendor_boot = replace_default_vendor_ramdisk(*vendor_boot, *new_ramdisk, *new_dtb); } else { new_vendor_boot = replace_vendor_ramdisk_fragment(ramdisk_name, *vendor_boot, *new_ramdisk); new_vendor_boot = replace_vendor_ramdisk_fragment(ramdisk_name, *vendor_boot, *new_ramdisk, *new_dtb); } if (!new_vendor_boot.ok()) return new_vendor_boot.error(); if (auto res = store_file(vendor_boot_fd, *new_vendor_boot, "new vendor boot image"); !res.ok()) Loading