oc::result<void> AndroidFormatWriter::finish_entry(File &file) { OUTCOME_TRYV(m_seg->finish_entry(file, m_writer)); auto swentry = m_seg->entry(); // Update SHA1 hash uint32_t le32_size = mb_htole32(*swentry->size); // Include size for everything except empty DT images if ((swentry->type != ENTRY_TYPE_DEVICE_TREE || *swentry->size > 0) && !SHA1_Update(&m_sha_ctx, &le32_size, sizeof(le32_size))) { m_writer.set_fatal(); return AndroidError::Sha1UpdateError; } switch (swentry->type) { case ENTRY_TYPE_KERNEL: m_hdr.kernel_size = *swentry->size; break; case ENTRY_TYPE_RAMDISK: m_hdr.ramdisk_size = *swentry->size; break; case ENTRY_TYPE_SECONDBOOT: m_hdr.second_size = *swentry->size; break; case ENTRY_TYPE_DEVICE_TREE: m_hdr.dt_size = *swentry->size; break; } return oc::success(); }
static oc::result<void> _mtk_header_update_size(Writer &writer, File &file, uint64_t offset, uint32_t size) { uint32_t le32_size = mb_htole32(size); if (offset > SIZE_MAX - offsetof(MtkHeader, size)) { writer.set_fatal(); return MtkError::MtkHeaderOffsetTooLarge; } auto seek_ret = file.seek( static_cast<int64_t>(offset + offsetof(MtkHeader, size)), SEEK_SET); if (!seek_ret) { if (file.is_fatal()) { writer.set_fatal(); } return seek_ret.as_failure(); } auto ret = file_write_exact(file, &le32_size, sizeof(le32_size)); if (!ret) { if (file.is_fatal()) { writer.set_fatal(); } return ret.as_failure(); } return oc::success(); }
MB_BEGIN_C_DECLS static bool _patch_shellcode(uint32_t header, uint32_t ramdisk, unsigned char patch[LOKI_SHELLCODE_SIZE]) { bool found_header = false; bool found_ramdisk = false; uint32_t *ptr; for (size_t i = 0; i < LOKI_SHELLCODE_SIZE - sizeof(uint32_t); ++i) { // Safe with little and big endian ptr = reinterpret_cast<uint32_t *>(&patch[i]); if (*ptr == 0xffffffff) { *ptr = mb_htole32(header); found_header = true; } else if (*ptr == 0xeeeeeeee) { *ptr = mb_htole32(ramdisk); found_ramdisk = true; } } return found_header && found_ramdisk; }
static oc::result<void> _mtk_compute_sha1(Writer &writer, SegmentWriter &seg, File &file, unsigned char digest[SHA_DIGEST_LENGTH]) { SHA_CTX sha_ctx; char buf[10240]; uint32_t kernel_mtkhdr_size = 0; uint32_t ramdisk_mtkhdr_size = 0; if (!SHA1_Init(&sha_ctx)) { return android::AndroidError::Sha1InitError; } for (auto const &entry : seg.entries()) { uint64_t remain = *entry.size; auto seek_ret = file.seek(static_cast<int64_t>(entry.offset), SEEK_SET); if (!seek_ret) { if (file.is_fatal()) { writer.set_fatal(); } return seek_ret.as_failure(); } // Update checksum with data while (remain > 0) { auto to_read = std::min<uint64_t>(remain, sizeof(buf)); auto ret = file_read_exact(file, buf, static_cast<size_t>(to_read)); if (!ret) { if (writer.is_fatal()) { writer.set_fatal(); } return ret.as_failure(); } if (!SHA1_Update(&sha_ctx, buf, static_cast<size_t>(to_read))) { return android::AndroidError::Sha1UpdateError; } remain -= to_read; } uint32_t le32_size; // Update checksum with size switch (entry.type) { case ENTRY_TYPE_MTK_KERNEL_HEADER: kernel_mtkhdr_size = *entry.size; continue; case ENTRY_TYPE_MTK_RAMDISK_HEADER: ramdisk_mtkhdr_size = *entry.size; continue; case ENTRY_TYPE_KERNEL: le32_size = mb_htole32(*entry.size + kernel_mtkhdr_size); break; case ENTRY_TYPE_RAMDISK: le32_size = mb_htole32(*entry.size + ramdisk_mtkhdr_size); break; case ENTRY_TYPE_SECONDBOOT: le32_size = mb_htole32(*entry.size); break; case ENTRY_TYPE_DEVICE_TREE: if (*entry.size == 0) { continue; } le32_size = mb_htole32(*entry.size); break; default: continue; } if (!SHA1_Update(&sha_ctx, &le32_size, sizeof(le32_size))) { return android::AndroidError::Sha1UpdateError; } } if (!SHA1_Final(digest, &sha_ctx)) { return android::AndroidError::Sha1UpdateError; } return oc::success(); }