From af7de300d216e4fc192b8c7e8e5fef8fb7aa3a86 Mon Sep 17 00:00:00 2001 From: cfig Date: Tue, 13 Aug 2019 00:06:30 +0800 Subject: [PATCH] change recoveryDtboOffset calculation in accordance with AOSP although google's algorithm is not good enough --- avb/Makefile | 11 ---- bbootimg/src/main/kotlin/avb/Avb.kt | 5 +- bbootimg/src/main/kotlin/avb/blob/Header.kt | 24 +++++++ .../main/kotlin/avb/desc/HashDescriptor.kt | 4 +- .../kotlin/avb/desc/HashTreeDescriptor.kt | 4 +- .../src/main/kotlin/bootimg/BootImgHeader.kt | 18 +++++- bbootimg/src/main/kotlin/bootimg/Packer.kt | 2 +- .../src/main/kotlin/packable/BootImgParser.kt | 4 ++ .../src/main/kotlin/packable/DtboParser.kt | 4 ++ .../src/main/kotlin/packable/IPackable.kt | 3 + .../src/main/kotlin/packable/VBMetaParser.kt | 4 ++ build.gradle | 63 +++---------------- tools/mkbootimg | 2 +- 13 files changed, 72 insertions(+), 76 deletions(-) delete mode 100644 avb/Makefile diff --git a/avb/Makefile b/avb/Makefile deleted file mode 100644 index 625ce1d..0000000 --- a/avb/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -t: - cp boot.img boot.img.orig - ./avbtool add_hash_footer \ - --image boot.img \ - --partition_size 33554432 \ - --partition_name boot \ - --algorithm SHA256_RSA4096 \ - --key avb_test_data/testkey_rsa4096.pem - ./avbtool info_image --image boot.img - ./avbtool erase_footer --image boot.img - -./avbtool info_image --image boot.img diff --git a/bbootimg/src/main/kotlin/avb/Avb.kt b/bbootimg/src/main/kotlin/avb/Avb.kt index 83ce953..7280bbe 100755 --- a/bbootimg/src/main/kotlin/avb/Avb.kt +++ b/bbootimg/src/main/kotlin/avb/Avb.kt @@ -11,6 +11,7 @@ import cfig.Helper.Companion.paddingWith import cfig.io.Struct3 import com.fasterxml.jackson.databind.ObjectMapper import org.apache.commons.codec.binary.Hex +import org.junit.Assert import org.slf4j.LoggerFactory import java.io.File import java.io.FileInputStream @@ -63,7 +64,7 @@ class Avb { val imgPaddingNeeded = Helper.round_to_multiple(newImageSize, BLOCK_SIZE) - newImageSize // + vbmeta + padding - val vbmetaOffset = File(image_file).length() + val vbmetaOffset = newImageSize + imgPaddingNeeded val vbmetaBlobWithPadding = vbmetaBlob.paddingWith(BLOCK_SIZE.toUInt()) // + DONT_CARE chunk @@ -92,7 +93,7 @@ class Avb { log.info("4/4 Appending AVB footer (${footerBlobWithPadding.size} bytes)...") fos.write(footerBlobWithPadding) } - + Assert.assertEquals("generated file size mismatch", partition_size, File(image_file).length()) log.info("addHashFooter($image_file) done.") } diff --git a/bbootimg/src/main/kotlin/avb/blob/Header.kt b/bbootimg/src/main/kotlin/avb/blob/Header.kt index 007d0ed..f691975 100644 --- a/bbootimg/src/main/kotlin/avb/blob/Header.kt +++ b/bbootimg/src/main/kotlin/avb/blob/Header.kt @@ -77,6 +77,30 @@ data class Header( this.required_libavb_version_minor = maxOf(required_libavb_version_minor, minor) } + //toplevel flags + enum class AvbVBMetaImageFlags(val inFlags: Int) { + AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED(1), + AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED(2 shl 1) + } + + //verify flags + enum class AvbSlotVerifyFlags(val inFlags: Int) { + AVB_SLOT_VERIFY_FLAGS_NONE(0), + AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR(1), + AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION(2), + AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION(4) + } + + //hash descriptor flags + enum class HashDescriptorFlags(val inFlags: Int) { + AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB(1) + } + + //hash tree descriptor flags + enum class HashTreeDescriptorFlags(val inFlags: Int) { + AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB(1) + } + companion object { private const val magic: String = "AVB0" const val SIZE = 256 diff --git a/bbootimg/src/main/kotlin/avb/desc/HashDescriptor.kt b/bbootimg/src/main/kotlin/avb/desc/HashDescriptor.kt index 842af35..770a26a 100755 --- a/bbootimg/src/main/kotlin/avb/desc/HashDescriptor.kt +++ b/bbootimg/src/main/kotlin/avb/desc/HashDescriptor.kt @@ -1,5 +1,6 @@ package avb.desc +import avb.blob.Header import cfig.Helper import cfig.io.Struct3 import org.apache.commons.codec.binary.Hex @@ -24,7 +25,7 @@ class HashDescriptor(var flags: UInt = 0U, var flagsInterpretation: String = "" get() { var ret = "" - if (this.flags and AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB == 1U) { + if (this.flags and Header.HashDescriptorFlags.AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB.inFlags.toUInt() == 1U) { ret += "1:no-A/B system" } else { ret += "0:A/B system" @@ -124,7 +125,6 @@ class HashDescriptor(var flags: UInt = 0U, private const val SIZE = 72 + RESERVED private const val FORMAT_STRING = "!3Q32s4L${RESERVED}x" private val log = LoggerFactory.getLogger(HashDescriptor::class.java) - private const val AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB = 1U } override fun toString(): String { diff --git a/bbootimg/src/main/kotlin/avb/desc/HashTreeDescriptor.kt b/bbootimg/src/main/kotlin/avb/desc/HashTreeDescriptor.kt index 0bffc7a..0c3b194 100755 --- a/bbootimg/src/main/kotlin/avb/desc/HashTreeDescriptor.kt +++ b/bbootimg/src/main/kotlin/avb/desc/HashTreeDescriptor.kt @@ -1,5 +1,6 @@ package avb.desc +import avb.blob.Header import cfig.Helper import cfig.io.Struct3 import java.io.InputStream @@ -24,7 +25,7 @@ class HashTreeDescriptor( var flagsInterpretation: String = "" get() { var ret = "" - if (this.flags and AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB == 1U) { + if (this.flags and Header.HashTreeDescriptorFlags.AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB.inFlags.toUInt() == 1U) { ret += "1:no-A/B system" } else { ret += "0:A/B system" @@ -97,6 +98,5 @@ class HashTreeDescriptor( private const val RESERVED = 60L private const val SIZE = 120 + RESERVED private const val FORMAT_STRING = "!2QL3Q3L2Q32s4L${RESERVED}x" - private const val AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB = 1U } } diff --git a/bbootimg/src/main/kotlin/bootimg/BootImgHeader.kt b/bbootimg/src/main/kotlin/bootimg/BootImgHeader.kt index 88454d3..d5edeee 100644 --- a/bbootimg/src/main/kotlin/bootimg/BootImgHeader.kt +++ b/bbootimg/src/main/kotlin/bootimg/BootImgHeader.kt @@ -12,6 +12,7 @@ import java.nio.ByteBuffer import java.nio.ByteOrder import java.security.MessageDigest import java.util.regex.Pattern +import kotlin.math.pow @ExperimentalUnsignedTypes open class BootImgHeader( @@ -178,6 +179,13 @@ open class BootImgHeader( return md.digest() } + private fun get_recovery_dtbo_offset(): UInt { + return Helper.round_to_multiple(this.headerSize, pageSize) + + Helper.round_to_multiple(this.kernelLength, pageSize) + + Helper.round_to_multiple(this.ramdiskLength, pageSize) + + Helper.round_to_multiple(this.secondBootloaderLength, pageSize) + } + private fun refresh() { val param = ParamConfig() //refresh kernel size @@ -205,14 +213,15 @@ open class BootImgHeader( this.recoveryDtboOffset = 0U } else { this.recoveryDtboLength = File(param.dtbo!!).length().toUInt() + this.recoveryDtboOffset = get_recovery_dtbo_offset().toULong() + log.warn("using fake recoveryDtboOffset $recoveryDtboOffset (as is in AOSP avbtool)") } - //refresh recovery dtbo size + //refresh dtb size if (0U == this.dtbLength) { param.dtb = null } else { this.dtbLength = File(param.dtb!!).length().toUInt() } - //refresh image hash val imageId = when (this.headerVersion) { 0U -> { @@ -233,6 +242,11 @@ open class BootImgHeader( fun encode(): ByteArray { this.refresh() + val pageSizeChoices: MutableSet = mutableSetOf().apply { + (11..14).forEach { add(2.0.pow(it).toLong()) } + } + Assert.assertTrue("invalid parameter [pageSize=$pageSize], (choose from $pageSizeChoices)", + pageSizeChoices.contains(pageSize.toLong())) return Struct3(FORMAT_STRING).pack( "ANDROID!", //10I diff --git a/bbootimg/src/main/kotlin/bootimg/Packer.kt b/bbootimg/src/main/kotlin/bootimg/Packer.kt index 7705d00..2967dc6 100644 --- a/bbootimg/src/main/kotlin/bootimg/Packer.kt +++ b/bbootimg/src/main/kotlin/bootimg/Packer.kt @@ -150,7 +150,7 @@ class Packer { //write FileOutputStream(cfg.info.output + ".clear", false).use { fos -> fos.write(encodedHeader) - fos.write(ByteArray(info2.pageSize.toInt() - encodedHeader.size)) + fos.write(ByteArray((Helper.round_to_multiple(encodedHeader.size.toUInt(), info2.pageSize) - encodedHeader.size.toUInt()).toInt())) } writeData(info2, cfg.info.output) diff --git a/bbootimg/src/main/kotlin/packable/BootImgParser.kt b/bbootimg/src/main/kotlin/packable/BootImgParser.kt index 950f72b..33dc6c6 100644 --- a/bbootimg/src/main/kotlin/packable/BootImgParser.kt +++ b/bbootimg/src/main/kotlin/packable/BootImgParser.kt @@ -9,6 +9,10 @@ import java.lang.IllegalArgumentException @ExperimentalUnsignedTypes class BootImgParser : IPackable { + override fun flash(fileName: String) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + private val log = LoggerFactory.getLogger(BootImgParser::class.java) override fun capabilities(): List { diff --git a/bbootimg/src/main/kotlin/packable/DtboParser.kt b/bbootimg/src/main/kotlin/packable/DtboParser.kt index d6c6cb2..6b19c31 100644 --- a/bbootimg/src/main/kotlin/packable/DtboParser.kt +++ b/bbootimg/src/main/kotlin/packable/DtboParser.kt @@ -12,6 +12,10 @@ import java.util.* @ExperimentalUnsignedTypes class DtboParser(val workDir: File) : IPackable { + override fun flash(fileName: String) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + constructor() : this(File(".")) private val log = LoggerFactory.getLogger(DtboParser::class.java) diff --git a/bbootimg/src/main/kotlin/packable/IPackable.kt b/bbootimg/src/main/kotlin/packable/IPackable.kt index b67b268..acb89f3 100644 --- a/bbootimg/src/main/kotlin/packable/IPackable.kt +++ b/bbootimg/src/main/kotlin/packable/IPackable.kt @@ -6,4 +6,7 @@ interface IPackable { } fun unpack(fileName: String = "dtbo.img") fun pack(fileName: String = "dtbo.img") + fun flash(fileName: String = "dtbo.img") { + + } } diff --git a/bbootimg/src/main/kotlin/packable/VBMetaParser.kt b/bbootimg/src/main/kotlin/packable/VBMetaParser.kt index 34769a6..370805b 100644 --- a/bbootimg/src/main/kotlin/packable/VBMetaParser.kt +++ b/bbootimg/src/main/kotlin/packable/VBMetaParser.kt @@ -4,6 +4,10 @@ import cfig.Avb @ExperimentalUnsignedTypes class VBMetaParser: IPackable { + override fun flash(fileName: String) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + override fun capabilities(): List { return listOf("^vbmeta\\.img$", "^vbmeta\\_[a-z]+.img$") } diff --git a/build.gradle b/build.gradle index d15ada8..340aef5 100644 --- a/build.gradle +++ b/build.gradle @@ -31,30 +31,8 @@ if (parseGradleVersion(gradle.gradleVersion) < 5) { logger.info("Gradle Version {}", gradle.gradleVersion) } -def workdir = 'build/unzip_boot' def GROUP_ANDROID = "Android" -project.ext.rootWorkDir = new File(workdir).getAbsolutePath() -String activeImg = "boot.img" -String activePath = "/boot" -if (new File("boot.img").exists()) { - activeImg = "boot.img" - activePath = "/boot" -} else if (new File("recovery.img").exists()) { - activeImg = "recovery.img" - activePath = "/recovery" -} else if (new File("recovery-two-step.img").exists()) { - activeImg = "recovery-two-step.img" - activePath = "/boot" -} else if (new File("vbmeta.img").exists()) { - activeImg = "vbmeta.img" - activePath = "/vbmeta" -} -project.ext.outClearIMg = new File(String.format("%s.clear", activeImg)).getAbsolutePath() -project.ext.mkbootimgBin = new File("tools/mkbootimg").getAbsolutePath() -project.ext.mkbootfsBin = new File("mkbootfs/build/exe/mkbootfs/mkbootfs").getAbsolutePath() -project.ext.avbtool = new File("avb/avbtool").getAbsolutePath() project.ext.bootSigner = new File("boot_signer/build/libs/boot_signer.jar").getAbsolutePath() -logger.warn("Active image target: " + activeImg) // ---------------------------------------------------------------------------- // tasks @@ -119,39 +97,6 @@ void Run(String inCmd, String inWorkdir = null) { Run(Arrays.asList(inCmd.split()), inWorkdir); } -void updateBootImage(String activeImg) { - String flashTarget = null; - switch (activeImg) { - case "boot.img": - case "recovery-two-step.img": - flashTarget = "/dev/block/by-name/boot"; - break; - case "recovery.img": - flashTarget = "/dev/block/by-name/recovery"; - break; - case "vbmeta.img": - flashTarget = "/dev/block/by-name/vbmeta"; - if (!new File(activeImg + ".signed").exists()) { - return; - } - break; - } - Run("adb root") - Run("adb push " + activeImg + ".signed /cache/") - List cmd2 = ["adb", "shell", "dd if=/cache/" + activeImg + ".signed of=" + flashTarget] - Run(cmd2) - cmd2 = ["adb", "shell", "rm -f /cache/" + activeImg + ".signed"]; - Run(cmd2) -} - -task flash { - group GROUP_ANDROID - doLast { - updateBootImage(activeImg) - updateBootImage("vbmeta.img") - } -} - void rebootRecovery() { Run("adb reboot recovery") } @@ -179,6 +124,14 @@ task pack(type: JavaExec, dependsOn: ["bbootimg:jar", "mkbootfs:mkbootfsExecutab args "pack" } +task flash(type: JavaExec, dependsOn: ["bbootimg:jar"]) { + group GROUP_ANDROID + main = "cfig.packable.PackableLauncherKt" + classpath = files("bbootimg/build/libs/bbootimg.jar") + maxHeapSize '512m' + args "flash" +} + int parseGradleVersion(String version) { Pattern VERSION_PATTERN = Pattern.compile("((\\d+)(\\.\\d+)+)(-(\\p{Alpha}+)-(\\w+))?(-(SNAPSHOT|\\d{14}([-+]\\d{4})?))?") Matcher matcher = VERSION_PATTERN.matcher(version) diff --git a/tools/mkbootimg b/tools/mkbootimg index 1d91c7a..c62481f 100755 --- a/tools/mkbootimg +++ b/tools/mkbootimg @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # Copyright 2015, The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License");