mirror of
https://github.com/chenxiaolong/avbroot.git
synced 2026-07-03 14:05:11 +02:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| da124e4e05 | |||
| 7b778515d1 | |||
| 98745afe33 | |||
| a47c501211 | |||
| f2e47a65d4 | |||
| e11ddd2ba7 | |||
| 5d66774d13 |
@@ -20,8 +20,6 @@ jobs:
|
||||
RUSTFLAGS: -C strip=symbols -C target-feature=+crt-static
|
||||
TARGETS: ${{ join(matrix.artifact.targets, ' ') || matrix.artifact.name }}
|
||||
ANDROID_API: ${{ matrix.artifact.android_api }}
|
||||
# https://aws.github.io/aws-lc-rs/requirements/windows.html#use-of-prebuilt-nasm-objects
|
||||
AWS_LC_SYS_PREBUILT_NASM: 1
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
@@ -7,6 +7,14 @@
|
||||
to update the actual links at the bottom of the file.
|
||||
-->
|
||||
|
||||
### Version 3.15.0
|
||||
|
||||
* Add support for changing the virtual A/B compression algorithm ([PR #437])
|
||||
* For devices that launched with Android <14, `--vabc-algo lz4` can significantly increase OTA installation speed when using a custom OTA updater app (with caveats). There is no difference when sideloading from recovery mode.
|
||||
* See [the documentation](#changing-virtual-ab-cow-compression-algorithm) for more details.
|
||||
* Switch back to the ring library now that it is maintained again ([PR #438])
|
||||
* Update dependencies ([PR #439])
|
||||
|
||||
### Version 3.14.0
|
||||
|
||||
* Report as many errors as possible before failing in `avbroot ota verify` and improve error messages ([Discussion #426], [PR #428], [PR #430])
|
||||
@@ -480,3 +488,6 @@ Behind-the-scenes changes:
|
||||
[PR #430]: https://github.com/chenxiaolong/avbroot/pull/430
|
||||
[PR #434]: https://github.com/chenxiaolong/avbroot/pull/434
|
||||
[PR #435]: https://github.com/chenxiaolong/avbroot/pull/435
|
||||
[PR #437]: https://github.com/chenxiaolong/avbroot/pull/437
|
||||
[PR #438]: https://github.com/chenxiaolong/avbroot/pull/438
|
||||
[PR #439]: https://github.com/chenxiaolong/avbroot/pull/439
|
||||
|
||||
Generated
+92
-223
@@ -70,7 +70,7 @@ version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -81,7 +81,7 @@ checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell",
|
||||
"windows-sys",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -110,11 +110,10 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "avbroot"
|
||||
version = "3.14.0"
|
||||
version = "3.15.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assert_matches",
|
||||
"aws-lc-rs",
|
||||
"base64",
|
||||
"bitflags",
|
||||
"bstr",
|
||||
@@ -147,8 +146,9 @@ dependencies = [
|
||||
"rand",
|
||||
"rayon",
|
||||
"regex",
|
||||
"ring",
|
||||
"rsa",
|
||||
"rustix 1.0.3",
|
||||
"rustix 1.0.5",
|
||||
"serde",
|
||||
"sha1",
|
||||
"sha2",
|
||||
@@ -164,29 +164,6 @@ dependencies = [
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aws-lc-rs"
|
||||
version = "1.12.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dabb68eb3a7aa08b46fddfd59a3d55c978243557a90ab804769f7e20e67d2b01"
|
||||
dependencies = [
|
||||
"aws-lc-sys",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aws-lc-sys"
|
||||
version = "0.27.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77926887776171ced7d662120a75998e444d3750c951abfe07f90da130514b1f"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"cc",
|
||||
"cmake",
|
||||
"dunce",
|
||||
"fs_extra",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
@@ -205,29 +182,6 @@ version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.69.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools 0.12.1",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"log",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
"syn 2.0.100",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.0"
|
||||
@@ -300,9 +254,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cap-primitives"
|
||||
version = "3.4.2"
|
||||
version = "3.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fc15faeed2223d8b8e8cc1857f5861935a06d06713c4ac106b722ae9ce3c369"
|
||||
checksum = "50ad0183a9659850877cefe8f5b87d564b2dd1fe78b18945813687f29c0a6878"
|
||||
dependencies = [
|
||||
"ambient-authority",
|
||||
"fs-set-times",
|
||||
@@ -311,15 +265,15 @@ dependencies = [
|
||||
"ipnet",
|
||||
"maybe-owned",
|
||||
"rustix 0.38.44",
|
||||
"windows-sys",
|
||||
"windows-sys 0.59.0",
|
||||
"winx",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cap-std"
|
||||
version = "3.4.2"
|
||||
version = "3.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3dbd3e8e8d093d6ccb4b512264869e1281cdb032f7940bd50b2894f96f25609"
|
||||
checksum = "1c41814365b796ed12688026cb90a1e03236a84ccf009628f9c43c8aa3af250a"
|
||||
dependencies = [
|
||||
"cap-primitives",
|
||||
"io-extras",
|
||||
@@ -329,9 +283,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cap-tempfile"
|
||||
version = "3.4.2"
|
||||
version = "3.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ffa1c0edc4958d742bab2e903e52f93ccee482072680e08d6ce0784873e65b1"
|
||||
checksum = "87f95996888e8bb5198a6f27f9f9454244d1ddf4cf82202808ad6b7d570e858e"
|
||||
dependencies = [
|
||||
"cap-std",
|
||||
"rand",
|
||||
@@ -350,24 +304,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.17"
|
||||
version = "1.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a"
|
||||
checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
@@ -390,22 +335,11 @@ dependencies = [
|
||||
"inout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.32"
|
||||
version = "4.5.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6088f3ae8c3608d19260cd7445411865a485688711b78b5be70d78cd96136f83"
|
||||
checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -413,9 +347,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.32"
|
||||
version = "4.5.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8"
|
||||
checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -450,15 +384,6 @@ version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cms"
|
||||
version = "0.2.3"
|
||||
@@ -544,12 +469,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ctrlc"
|
||||
version = "3.4.5"
|
||||
version = "3.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3"
|
||||
checksum = "697b5419f348fd5ae2478e8018cb016c00a5881c7f46c717de98ffd135a5651c"
|
||||
dependencies = [
|
||||
"nix",
|
||||
"windows-sys",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -629,22 +554,16 @@ version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecb08c4819242b1ec89b3d0c6affa229005bef46ae4f7eed8b80768187c10087"
|
||||
|
||||
[[package]]
|
||||
name = "dunce"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
|
||||
|
||||
[[package]]
|
||||
name = "e2e"
|
||||
version = "3.14.0"
|
||||
version = "3.15.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"avbroot",
|
||||
"aws-lc-rs",
|
||||
"clap",
|
||||
"ctrlc",
|
||||
"hex",
|
||||
"ring",
|
||||
"rsa",
|
||||
"serde",
|
||||
"tempfile",
|
||||
@@ -670,12 +589,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.10"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
||||
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -698,15 +617,15 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
||||
|
||||
[[package]]
|
||||
name = "flagset"
|
||||
version = "0.4.6"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3ea1ec5f8307826a5b71094dd91fc04d4ae75d5709b20ad351c7fb4815c86ec"
|
||||
checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.0"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc"
|
||||
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"libz-rs-sys",
|
||||
@@ -726,19 +645,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94e7099f6313ecacbe1256e8ff9d617b75d1bcb16a6fddef94866d225a01a14a"
|
||||
dependencies = [
|
||||
"io-lifetimes",
|
||||
"rustix 1.0.3",
|
||||
"windows-sys",
|
||||
"rustix 1.0.5",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs_extra"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
|
||||
|
||||
[[package]]
|
||||
name = "fuzz"
|
||||
version = "3.14.0"
|
||||
version = "3.15.0"
|
||||
dependencies = [
|
||||
"avbroot",
|
||||
"honggfuzz",
|
||||
@@ -800,12 +713,6 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.2"
|
||||
@@ -836,15 +743,6 @@ dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "home"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "honggfuzz"
|
||||
version = "0.5.57"
|
||||
@@ -866,9 +764,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.8.0"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
|
||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
@@ -891,7 +789,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2285ddfe3054097ef4b2fe909ef8c3bcd1ea52a8f0d274416caebeef39f04a65"
|
||||
dependencies = [
|
||||
"io-lifetimes",
|
||||
"windows-sys",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -912,15 +810,6 @@ version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.14.0"
|
||||
@@ -938,10 +827,11 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.32"
|
||||
version = "0.1.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
|
||||
checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a"
|
||||
dependencies = [
|
||||
"getrandom 0.3.2",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@@ -954,12 +844,6 @@ dependencies = [
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "libbz2-rs-sys"
|
||||
version = "0.1.3"
|
||||
@@ -972,16 +856,6 @@ version = "0.2.171"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "liblzma"
|
||||
version = "0.3.6"
|
||||
@@ -1010,9 +884,9 @@ checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
|
||||
|
||||
[[package]]
|
||||
name = "libz-rs-sys"
|
||||
version = "0.4.2"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "902bc563b5d65ad9bba616b490842ef0651066a1a1dc3ce1087113ffcb873c8d"
|
||||
checksum = "6489ca9bd760fe9642d7644e827b0c9add07df89857b0416ee15c1cc1a3b8c5a"
|
||||
dependencies = [
|
||||
"zlib-rs",
|
||||
]
|
||||
@@ -1031,9 +905,9 @@ checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.26"
|
||||
version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "logos"
|
||||
@@ -1121,17 +995,11 @@ dependencies = [
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.5"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
|
||||
checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
@@ -1154,16 +1022,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
@@ -1224,9 +1082,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.1"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
@@ -1375,9 +1233,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.31"
|
||||
version = "0.2.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5316f57387668042f561aae71480de936257848f9c43ce528e311d89a07cadeb"
|
||||
checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn 2.0.100",
|
||||
@@ -1409,7 +1267,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"itertools 0.14.0",
|
||||
"itertools",
|
||||
"log",
|
||||
"multimap",
|
||||
"once_cell",
|
||||
@@ -1429,7 +1287,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.14.0",
|
||||
"itertools",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
@@ -1578,6 +1436,20 @@ version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"getrandom 0.2.15",
|
||||
"libc",
|
||||
"untrusted",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rsa"
|
||||
version = "0.9.8"
|
||||
@@ -1600,12 +1472,6 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
@@ -1627,20 +1493,20 @@ dependencies = [
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.15",
|
||||
"once_cell",
|
||||
"windows-sys",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.0.3"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96"
|
||||
checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.9.3",
|
||||
"windows-sys",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1753,9 +1619,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.14.0"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
|
||||
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
@@ -1828,8 +1694,8 @@ dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.3.2",
|
||||
"once_cell",
|
||||
"rustix 1.0.3",
|
||||
"windows-sys",
|
||||
"rustix 1.0.5",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2016,6 +1882,12 @@ version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
@@ -2058,18 +1930,6 @@ dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
|
||||
dependencies = [
|
||||
"either",
|
||||
"home",
|
||||
"once_cell",
|
||||
"rustix 0.38.44",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
@@ -2092,6 +1952,15 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
@@ -2181,7 +2050,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f3fd376f71958b862e7afb20cfe5a22830e1963462f3a17f49d82a6c1d1f42d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"windows-sys",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2209,7 +2078,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "xtask"
|
||||
version = "3.14.0"
|
||||
version = "3.15.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -2270,6 +2139,6 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zlib-rs"
|
||||
version = "0.4.2"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b20717f0917c908dc63de2e44e97f1e6b126ca58d0e391cee86d504eb8fbd05"
|
||||
checksum = "868b928d7949e09af2f6086dfc1e01936064cc7a819253bce650d4e2a2d63ba8"
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ members = ["avbroot", "e2e", "fuzz", "xtask"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
version = "3.14.0"
|
||||
version = "3.15.0"
|
||||
license = "GPL-3.0-only"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/chenxiaolong/avbroot"
|
||||
|
||||
@@ -431,6 +431,18 @@ Verified boot is disabled by vbmeta's header flags: 0x3
|
||||
|
||||
To forcibly enable AVB (by clearing the flags), pass in `--clear-vbmeta-flags`.
|
||||
|
||||
### Changing virtual A/B CoW compression algorithm
|
||||
|
||||
The virtual A/B CoW compression algorithm can be changed by passing in `--vabc-algo <algo>` with `gz` or `lz4`. OTAs normally use an algorithm that is compatible with the initial version of Android shipped on the device.
|
||||
|
||||
* Devices launching with Android 12 support `gz` and `brotli` (unsupported by avbroot)
|
||||
* Devices launching with Android 14 support `lz4`
|
||||
* Devices launching with Android 15 support `zstd` (unsupported by avbroot)
|
||||
|
||||
Picking a fast algorithm, like lz4, can speed up OTA installation significantly when installing via a custom OTA updater app. However, there is no performance difference when sideloading an OTA from recovery mode.
|
||||
|
||||
Note that the currently running version of Android must support the specified compression algorithm or else the OTA will fail to install. For example, trying to install an Android 14 OTA that uses lz4 CoW compression will fail if the running system is Android 13.
|
||||
|
||||
### Non-interactive use
|
||||
|
||||
avbroot prompts for the private key passphrases interactively by default. To run avbroot non-interactively, either:
|
||||
|
||||
+5
-5
@@ -10,11 +10,6 @@ publish = false
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.75"
|
||||
# We use aws-lc-rs instead of sha2 for sha256 digest computation of large files
|
||||
# because sha2 is significantly slower on older x86_64 CPUs without the SHA-NI
|
||||
# instructions. sha2 is still used for signing purposes.
|
||||
# https://github.com/RustCrypto/hashes/issues/327
|
||||
aws-lc-rs = { version = "1.0.0", default-features = false, features = ["aws-lc-sys"] }
|
||||
base64 = "0.22.1"
|
||||
bitflags = { version = "2.4.1", features = ["serde"] }
|
||||
bstr = "1.6.2"
|
||||
@@ -46,6 +41,11 @@ prost = "0.13.1"
|
||||
rand = "0.8.5"
|
||||
rayon = "1.7.0"
|
||||
regex = { version = "1.9.4", default-features = false, features = ["perf", "std"] }
|
||||
# We use ring instead of sha2 for sha256 digest computation of large files
|
||||
# because sha2 is significantly slower on older x86_64 CPUs without the SHA-NI
|
||||
# instructions. sha2 is still used for signing purposes.
|
||||
# https://github.com/RustCrypto/hashes/issues/327
|
||||
ring = "0.17.14"
|
||||
rsa = { version = "0.9.2", features = ["sha1", "sha2"] }
|
||||
serde = { version = "1.0.188", features = ["derive"] }
|
||||
sha1 = "0.10.5"
|
||||
|
||||
@@ -599,7 +599,7 @@ pub fn verify_descriptors(
|
||||
fn compute_digest_recursive(
|
||||
directory: &Dir,
|
||||
name: &str,
|
||||
context: &mut aws_lc_rs::digest::Context,
|
||||
context: &mut ring::digest::Context,
|
||||
max_depth: u8,
|
||||
seen: &mut HashSet<String>,
|
||||
cancel_signal: &AtomicBool,
|
||||
@@ -670,7 +670,7 @@ fn compute_digest_recursive(
|
||||
/// chained partitions more than one level deep are ignored.
|
||||
pub fn compute_digest(directory: &Dir, name: &str, cancel_signal: &AtomicBool) -> Result<[u8; 32]> {
|
||||
let mut seen = HashSet::<String>::new();
|
||||
let mut context = aws_lc_rs::digest::Context::new(&aws_lc_rs::digest::SHA256);
|
||||
let mut context = ring::digest::Context::new(&ring::digest::SHA256);
|
||||
|
||||
compute_digest_recursive(directory, name, &mut context, 2, &mut seen, cancel_signal)?;
|
||||
|
||||
|
||||
+280
-118
@@ -14,9 +14,10 @@ use std::{
|
||||
};
|
||||
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use bitflags::bitflags;
|
||||
use cap_std::{ambient_authority, fs::Dir};
|
||||
use cap_tempfile::TempDir;
|
||||
use clap::{value_parser, ArgAction, Args, Parser, Subcommand};
|
||||
use clap::{value_parser, ArgAction, Args, Parser, Subcommand, ValueEnum};
|
||||
use rayon::{iter::IntoParallelRefIterator, prelude::ParallelIterator};
|
||||
use tempfile::NamedTempFile;
|
||||
use topological_sort::TopologicalSort;
|
||||
@@ -72,48 +73,65 @@ fn sorted<T: Ord>(iter: impl Iterator<Item = T>) -> Vec<T> {
|
||||
items
|
||||
}
|
||||
|
||||
pub struct RequiredImages(HashSet<String>);
|
||||
bitflags! {
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct PartitionFlags: u8 {
|
||||
const BOOT = 1 << 0;
|
||||
const SYSTEM = 1 << 1;
|
||||
const VBMETA = 1 << 2;
|
||||
const COW = 1 << 3;
|
||||
|
||||
impl RequiredImages {
|
||||
pub fn new(manifest: &DeltaArchiveManifest) -> Self {
|
||||
let partitions = manifest
|
||||
.partitions
|
||||
.iter()
|
||||
.map(|p| &p.partition_name)
|
||||
.filter(|n| Self::is_boot(n) || Self::is_system(n) || Self::is_vbmeta(n))
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
Self(partitions)
|
||||
const KNOWN = Self::BOOT.bits() | Self::SYSTEM.bits() | Self::VBMETA.bits();
|
||||
}
|
||||
|
||||
pub fn is_boot(name: &str) -> bool {
|
||||
name == "boot" || name == "init_boot" || name == "recovery" || name == "vendor_boot"
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct RequiredFlags: u8 {
|
||||
const SYSTEM = 1 << 0;
|
||||
const ALL_COW = 1 << 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the images required for patching. If [`RequiredFlags::SYSTEM`] is
|
||||
/// specified, then the system image is included. If [`RequiredFlags::ALL_COW`]
|
||||
/// is specified, then all images with CoW size estimates are included.
|
||||
pub fn get_required_images(
|
||||
manifest: &DeltaArchiveManifest,
|
||||
required_flags: RequiredFlags,
|
||||
) -> HashMap<String, PartitionFlags> {
|
||||
let mut result = HashMap::new();
|
||||
|
||||
for partition in &manifest.partitions {
|
||||
let name = &partition.partition_name;
|
||||
let mut flags = PartitionFlags::empty();
|
||||
|
||||
if name == "boot" || name == "init_boot" || name == "recovery" || name == "vendor_boot" {
|
||||
flags |= PartitionFlags::BOOT;
|
||||
} else if required_flags.contains(RequiredFlags::SYSTEM) && name == "system" {
|
||||
flags |= PartitionFlags::SYSTEM;
|
||||
} else if name.starts_with("vbmeta") {
|
||||
flags |= PartitionFlags::VBMETA;
|
||||
}
|
||||
|
||||
if partition.estimate_cow_size.is_some() {
|
||||
flags |= PartitionFlags::COW;
|
||||
}
|
||||
|
||||
// Skip completely unrecognized partitions.
|
||||
if flags.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip unrecognized CoW partitions unless we ask for them.
|
||||
if flags == PartitionFlags::COW && !required_flags.contains(RequiredFlags::ALL_COW) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result.insert(name.clone(), flags);
|
||||
}
|
||||
|
||||
pub fn is_system(name: &str) -> bool {
|
||||
name == "system"
|
||||
}
|
||||
|
||||
pub fn is_vbmeta(name: &str) -> bool {
|
||||
name.starts_with("vbmeta")
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = &str> {
|
||||
self.0.iter().map(|n| n.as_str())
|
||||
}
|
||||
|
||||
pub fn iter_boot(&self) -> impl Iterator<Item = &str> {
|
||||
self.iter().filter(|n| Self::is_boot(n))
|
||||
}
|
||||
|
||||
pub fn iter_system(&self) -> impl Iterator<Item = &str> {
|
||||
self.iter().filter(|n| Self::is_system(n))
|
||||
}
|
||||
|
||||
pub fn iter_vbmeta(&self) -> impl Iterator<Item = &str> {
|
||||
self.iter().filter(|n| Self::is_vbmeta(n))
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
@@ -134,7 +152,7 @@ struct InputFile {
|
||||
/// operating system).
|
||||
fn open_input_files(
|
||||
payload: &(dyn ReadSeekReopen + Sync),
|
||||
required_images: &RequiredImages,
|
||||
required_images: &HashMap<String, PartitionFlags>,
|
||||
external_images: &HashMap<String, PathBuf>,
|
||||
header: &PayloadHeader,
|
||||
cancel_signal: &AtomicBool,
|
||||
@@ -144,8 +162,8 @@ fn open_input_files(
|
||||
// We always include replacement images that the user specifies, even if
|
||||
// they don't need to be patched.
|
||||
let all_images = required_images
|
||||
.iter()
|
||||
.chain(external_images.keys().map(|k| k.as_str()))
|
||||
.keys()
|
||||
.chain(external_images.keys())
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
for name in all_images {
|
||||
@@ -158,7 +176,7 @@ fn open_input_files(
|
||||
.map(PSeekFile::new)
|
||||
.with_context(|| format!("Failed to open external image: {path:?}"))?;
|
||||
input_files.insert(
|
||||
name.to_owned(),
|
||||
name.clone(),
|
||||
InputFile {
|
||||
file,
|
||||
state: InputFileState::External,
|
||||
@@ -174,7 +192,7 @@ fn open_input_files(
|
||||
payload::extract_image(payload, &file, header, name, cancel_signal)
|
||||
.with_context(|| format!("Failed to extract from original payload: {name}"))?;
|
||||
input_files.insert(
|
||||
name.to_owned(),
|
||||
name.clone(),
|
||||
InputFile {
|
||||
file,
|
||||
state: InputFileState::Extracted,
|
||||
@@ -190,15 +208,19 @@ fn open_input_files(
|
||||
/// necessarily patched. Each patcher will determine which image it should
|
||||
/// target. If the original image is signed, then it will be re-signed with
|
||||
/// `key_avb`.
|
||||
fn patch_boot_images<'a, 'b: 'a>(
|
||||
required_images: &'b RequiredImages,
|
||||
fn patch_boot_images(
|
||||
required_images: &HashMap<String, PartitionFlags>,
|
||||
input_files: &mut HashMap<String, InputFile>,
|
||||
boot_patchers: &[Box<dyn BootImagePatch + Sync>],
|
||||
key_avb: &RsaSigningKey,
|
||||
cancel_signal: &AtomicBool,
|
||||
) -> Result<()> {
|
||||
let input_files = Mutex::new(input_files);
|
||||
let boot_partitions = required_images.iter_boot().collect::<Vec<_>>();
|
||||
let boot_partitions = required_images
|
||||
.iter()
|
||||
.filter(|(_, flags)| flags.contains(PartitionFlags::BOOT))
|
||||
.map(|(name, _)| name.as_str())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
info!(
|
||||
"Candidate boot images: {}",
|
||||
@@ -234,16 +256,23 @@ fn patch_boot_images<'a, 'b: 'a>(
|
||||
|
||||
/// Patch the single system image listed in `required_images` to replace the
|
||||
/// `otacerts.zip` contents.
|
||||
fn patch_system_image<'a, 'b: 'a>(
|
||||
required_images: &'b RequiredImages,
|
||||
fn patch_system_image<'a>(
|
||||
required_images: &'a HashMap<String, PartitionFlags>,
|
||||
input_files: &mut HashMap<String, InputFile>,
|
||||
cert_ota: &Certificate,
|
||||
key_avb: &RsaSigningKey,
|
||||
cancel_signal: &AtomicBool,
|
||||
) -> Result<(&'b str, Vec<Range<u64>>)> {
|
||||
let Some(target) = required_images.iter_system().next() else {
|
||||
) -> Result<(&'a str, Vec<Range<u64>>)> {
|
||||
let mut system_iter = required_images
|
||||
.iter()
|
||||
.filter(|(_, flags)| flags.contains(PartitionFlags::SYSTEM))
|
||||
.map(|(name, _)| name);
|
||||
let Some(target) = system_iter.next() else {
|
||||
bail!("No system partition found");
|
||||
};
|
||||
if system_iter.next().is_some() {
|
||||
bail!("Multiple system partitions found");
|
||||
};
|
||||
|
||||
let _span = debug_span!("image", name = target).entered();
|
||||
|
||||
@@ -309,12 +338,13 @@ fn load_vbmeta_images(
|
||||
/// Check that all critical partitions within the payload are protected by a
|
||||
/// vbmeta image in `vbmeta_headers`.
|
||||
fn ensure_partitions_protected(
|
||||
required_images: &RequiredImages,
|
||||
required_images: &HashMap<String, PartitionFlags>,
|
||||
vbmeta_headers: &HashMap<String, Header>,
|
||||
) -> Result<()> {
|
||||
let critical_partitions = required_images
|
||||
.iter_boot()
|
||||
.chain(required_images.iter_vbmeta())
|
||||
.iter()
|
||||
.filter(|(_, flags)| flags.intersects(PartitionFlags::BOOT | PartitionFlags::VBMETA))
|
||||
.map(|(name, _)| name.as_str())
|
||||
.collect::<BTreeSet<_>>();
|
||||
|
||||
// vbmeta partitions first.
|
||||
@@ -546,6 +576,58 @@ fn update_metadata_descriptors(parent_header: &mut Header, child_header: &Header
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the VABC algorithm from the payload header. This will fail if an
|
||||
/// unsupported VABC algorithm is specified, but not if VABC is disabled.
|
||||
fn get_vabc_algo(header: &PayloadHeader) -> Result<Option<VabcAlgo>> {
|
||||
// Only CoW v2 seems to exist in the wild currently, so that is all we
|
||||
// support.
|
||||
let Some(dpm) = &header.manifest.dynamic_partition_metadata else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
if !dpm.vabc_enabled() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let cow_version = dpm.cow_version();
|
||||
if dpm.cow_version() != 2 {
|
||||
bail!("Unsupported CoW version: {cow_version}");
|
||||
}
|
||||
|
||||
let compression = dpm.vabc_compression_param();
|
||||
let Ok(vabc_algo) = VabcAlgo::from_str(compression, false) else {
|
||||
bail!("Unsupported VABC compression: {compression}");
|
||||
};
|
||||
|
||||
Ok(Some(vabc_algo))
|
||||
}
|
||||
|
||||
/// Set the VABC algorithm in the payload header and return whether it was
|
||||
/// changed. This will fail if VABC was originally disabled. Returns whether the
|
||||
/// new algorithm is different from the old algorithm.
|
||||
fn set_vabc_algo(header: &mut PayloadHeader, vabc_algo: VabcAlgo) -> Result<bool> {
|
||||
let Some(dpm) = &mut header.manifest.dynamic_partition_metadata else {
|
||||
bail!("Dynamic partition metadata is missing");
|
||||
};
|
||||
|
||||
if !dpm.vabc_enabled() {
|
||||
bail!("Cannot change VABC algorithm when VABC is disabled");
|
||||
}
|
||||
|
||||
let compression = dpm.vabc_compression_param();
|
||||
let Ok(old_vabc_algo) = VabcAlgo::from_str(compression, false) else {
|
||||
bail!("Unsupported VABC compression: {compression}");
|
||||
};
|
||||
|
||||
if vabc_algo == old_vabc_algo {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
dpm.vabc_compression_param = Some(vabc_algo.to_string());
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
/// Update vbmeta headers.
|
||||
///
|
||||
/// * If [`Header::flags`] is non-zero, then an error is returned because the
|
||||
@@ -566,6 +648,11 @@ fn update_vbmeta_headers(
|
||||
key: &RsaSigningKey,
|
||||
block_size: u64,
|
||||
) -> Result<()> {
|
||||
info!(
|
||||
"Patching vbmeta images: {}",
|
||||
joined(order.iter().map(|(n, _)| n)),
|
||||
);
|
||||
|
||||
for (name, deps) in order {
|
||||
let parent_header = headers.get_mut(name).unwrap();
|
||||
let orig_parent_header = parent_header.clone();
|
||||
@@ -644,6 +731,7 @@ pub fn compress_image(
|
||||
.map(PSeekFile::new)
|
||||
.with_context(|| format!("Failed to create temp file for: {name}"))?;
|
||||
|
||||
let vabc_algo = get_vabc_algo(header)?;
|
||||
let block_size = header.manifest.block_size();
|
||||
let partition = header
|
||||
.manifest
|
||||
@@ -652,6 +740,20 @@ pub fn compress_image(
|
||||
.find(|p| p.partition_name == name)
|
||||
.unwrap();
|
||||
|
||||
// If VABC is enabled, we need to update the CoW size estimate or else the
|
||||
// CoW block device may run out of space during flashing.
|
||||
let vabc_algo = if partition.estimate_cow_size.is_some() {
|
||||
let Some(vabc_algo) = vabc_algo else {
|
||||
bail!("Partition has CoW estimate, but VABC is disabled: {name}");
|
||||
};
|
||||
|
||||
info!("Needs updated {vabc_algo} CoW size estimate: {name}");
|
||||
|
||||
Some(vabc_algo)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(r) = ranges {
|
||||
info!("Compressing partial image: {name}: {r:?}");
|
||||
|
||||
@@ -665,7 +767,23 @@ pub fn compress_image(
|
||||
cancel_signal,
|
||||
) {
|
||||
Ok(indices) => {
|
||||
// The changes we make usually aren't any less compressible, but
|
||||
// we'll still recompute the CoW size estimate to handle the
|
||||
// case where the user requested a different algorithm.
|
||||
if let Some(vabc_algo) = vabc_algo {
|
||||
let cow_estimate = payload::compute_cow_estimate(
|
||||
&*file,
|
||||
name,
|
||||
block_size,
|
||||
vabc_algo,
|
||||
cancel_signal,
|
||||
)?;
|
||||
|
||||
partition.estimate_cow_size = Some(cow_estimate);
|
||||
}
|
||||
|
||||
*file = writer;
|
||||
|
||||
return Ok(indices);
|
||||
}
|
||||
// If we can't take advantage of the optimization, we can still
|
||||
@@ -679,37 +797,6 @@ pub fn compress_image(
|
||||
|
||||
info!("Compressing full image: {name}");
|
||||
|
||||
// Otherwise, compress the entire image. If VABC is enabled, we need to
|
||||
// update the CoW size estimate or else the CoW block device may run out of
|
||||
// space during flashing.
|
||||
let vabc_algo = if partition.estimate_cow_size.is_some() {
|
||||
// Only CoW v2 seems to exist in the wild currently, so that is all we
|
||||
// support.
|
||||
let Some(dpm) = &header.manifest.dynamic_partition_metadata else {
|
||||
bail!("Dynamic partition metadata is missing");
|
||||
};
|
||||
|
||||
if !dpm.vabc_enabled() {
|
||||
bail!("Partition has CoW estimate, but VABC is disabled: {name}");
|
||||
}
|
||||
|
||||
let cow_version = dpm.cow_version();
|
||||
if dpm.cow_version() != 2 {
|
||||
bail!("Unsupported CoW version: {cow_version}");
|
||||
}
|
||||
|
||||
let compression = dpm.vabc_compression_param();
|
||||
let Some(vabc_algo) = VabcAlgo::new(compression) else {
|
||||
bail!("Unsupported VABC compression: {compression}");
|
||||
};
|
||||
|
||||
info!("Needs updated {vabc_algo} CoW size estimate: {name}");
|
||||
|
||||
Some(vabc_algo)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let (partition_info, operations, cow_estimate) =
|
||||
payload::compress_image(&*file, &writer, name, block_size, vabc_algo, cancel_signal)?;
|
||||
|
||||
@@ -723,6 +810,45 @@ pub fn compress_image(
|
||||
Ok(vec![0..partition.operations.len()])
|
||||
}
|
||||
|
||||
/// Recompute the CoW estimate for an image and update the OTA manifest
|
||||
/// partition entry appropriately. The input file is not modified.
|
||||
fn recow_image(
|
||||
name: &str,
|
||||
file: &mut PSeekFile,
|
||||
header: &mut PayloadHeader,
|
||||
cancel_signal: &AtomicBool,
|
||||
) -> Result<()> {
|
||||
let _span = debug_span!("image", name).entered();
|
||||
|
||||
file.rewind()?;
|
||||
|
||||
let vabc_algo = get_vabc_algo(header)?;
|
||||
let block_size = header.manifest.block_size();
|
||||
let partition = header
|
||||
.manifest
|
||||
.partitions
|
||||
.iter_mut()
|
||||
.find(|p| p.partition_name == name)
|
||||
.unwrap();
|
||||
|
||||
if partition.estimate_cow_size.is_none() {
|
||||
bail!("Partition has no original CoW estimate: {name}");
|
||||
};
|
||||
|
||||
let Some(vabc_algo) = vabc_algo else {
|
||||
bail!("Partition has CoW estimate, but VABC is disabled: {name}");
|
||||
};
|
||||
|
||||
info!("Recomputing {vabc_algo} CoW size estimate: {name}");
|
||||
|
||||
let cow_estimate =
|
||||
payload::compute_cow_estimate(&*file, name, block_size, vabc_algo, cancel_signal)?;
|
||||
|
||||
partition.estimate_cow_size = Some(cow_estimate);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn patch_ota_payload(
|
||||
payload: &(dyn ReadSeekReopen + Sync),
|
||||
@@ -731,6 +857,7 @@ fn patch_ota_payload(
|
||||
boot_patchers: &[Box<dyn BootImagePatch + Sync>],
|
||||
skip_system_ota_cert: bool,
|
||||
clear_vbmeta_flags: bool,
|
||||
vabc_algo_override: Option<VabcAlgo>,
|
||||
key_avb: &RsaSigningKey,
|
||||
key_ota: &RsaSigningKey,
|
||||
cert_ota: &Certificate,
|
||||
@@ -742,6 +869,16 @@ fn patch_ota_payload(
|
||||
bail!("Payload is a delta OTA, not a full OTA");
|
||||
}
|
||||
|
||||
let mut required_flags = RequiredFlags::empty();
|
||||
if !skip_system_ota_cert {
|
||||
required_flags |= RequiredFlags::SYSTEM;
|
||||
}
|
||||
if let Some(vabc_algo) = vabc_algo_override {
|
||||
if set_vabc_algo(&mut header, vabc_algo)? {
|
||||
required_flags |= RequiredFlags::ALL_COW;
|
||||
}
|
||||
}
|
||||
|
||||
let all_partitions = header
|
||||
.manifest
|
||||
.partitions
|
||||
@@ -757,11 +894,17 @@ fn patch_ota_payload(
|
||||
}
|
||||
}
|
||||
|
||||
// Determine what images need to be patched. For simplicity, we pre-read all
|
||||
// vbmeta images since they're tiny. They're discarded later if the they
|
||||
// don't need to be modified.
|
||||
let required_images = RequiredImages::new(&header.manifest);
|
||||
let vbmeta_images = required_images.iter_vbmeta().collect::<HashSet<_>>();
|
||||
let required_images = get_required_images(&header.manifest, required_flags);
|
||||
let vbmeta_images = required_images
|
||||
.iter()
|
||||
.filter(|(_, flags)| flags.contains(PartitionFlags::VBMETA))
|
||||
.map(|(name, _)| name.as_str())
|
||||
.collect::<HashSet<_>>();
|
||||
let cow_images = required_images
|
||||
.iter()
|
||||
.filter(|(_, flags)| flags.contains(PartitionFlags::COW))
|
||||
.map(|(name, _)| name.as_str())
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
// The set of source images to be inserted into the new payload, replacing
|
||||
// what was in the original payload. Initially, this refers to either user
|
||||
@@ -784,9 +927,6 @@ fn patch_ota_payload(
|
||||
cancel_signal,
|
||||
)?;
|
||||
|
||||
input_files
|
||||
.retain(|n, f| !(f.state == InputFileState::Extracted && RequiredImages::is_boot(n)));
|
||||
|
||||
let system_result = if skip_system_ota_cert {
|
||||
None
|
||||
} else {
|
||||
@@ -799,20 +939,12 @@ fn patch_ota_payload(
|
||||
)?)
|
||||
};
|
||||
|
||||
input_files
|
||||
.retain(|n, f| !(f.state == InputFileState::Extracted && RequiredImages::is_system(n)));
|
||||
|
||||
let mut vbmeta_headers = load_vbmeta_images(&mut input_files, &vbmeta_images)?;
|
||||
|
||||
ensure_partitions_protected(&required_images, &vbmeta_headers)?;
|
||||
|
||||
let mut vbmeta_order = get_vbmeta_patch_order(&input_files, &vbmeta_headers)?;
|
||||
|
||||
info!(
|
||||
"Patching vbmeta images: {}",
|
||||
joined(vbmeta_order.iter().map(|(n, _)| n)),
|
||||
);
|
||||
|
||||
update_vbmeta_headers(
|
||||
&mut input_files,
|
||||
&mut vbmeta_headers,
|
||||
@@ -822,7 +954,19 @@ fn patch_ota_payload(
|
||||
header.manifest.block_size().into(),
|
||||
)?;
|
||||
|
||||
// Unmodified vbmeta images no longer need to be kept around either.
|
||||
// Recompute CoW estimates for partitions we don't modify.
|
||||
input_files
|
||||
.iter_mut()
|
||||
.filter(|(name, f)| {
|
||||
f.state == InputFileState::Extracted && cow_images.contains(name.as_str())
|
||||
})
|
||||
.try_for_each(|(name, input_file)| {
|
||||
recow_image(name, &mut input_file.file, &mut header, cancel_signal)
|
||||
})?;
|
||||
|
||||
// Drop all unmodified images. We only want to compress modified images.
|
||||
// For recowed images, the payload header was already updated with the new
|
||||
// estimate. The actual data can be copied from the original payload.
|
||||
input_files.retain(|_, f| f.state != InputFileState::Extracted);
|
||||
|
||||
let mut compressed_files = input_files
|
||||
@@ -933,6 +1077,7 @@ fn patch_ota_zip(
|
||||
boot_patchers: &[Box<dyn BootImagePatch + Sync>],
|
||||
skip_system_ota_cert: bool,
|
||||
clear_vbmeta_flags: bool,
|
||||
vabc_algo_override: Option<VabcAlgo>,
|
||||
zip_mode: ZipMode,
|
||||
key_avb: &RsaSigningKey,
|
||||
key_ota: &RsaSigningKey,
|
||||
@@ -1056,6 +1201,7 @@ fn patch_ota_zip(
|
||||
boot_patchers,
|
||||
skip_system_ota_cert,
|
||||
clear_vbmeta_flags,
|
||||
vabc_algo_override,
|
||||
key_avb,
|
||||
key_ota,
|
||||
cert_ota,
|
||||
@@ -1201,7 +1347,7 @@ fn verify_partition_hashes(
|
||||
|
||||
let mut writer = HashingWriter::new(
|
||||
io::sink(),
|
||||
aws_lc_rs::digest::Context::new(&aws_lc_rs::digest::SHA256),
|
||||
ring::digest::Context::new(&ring::digest::SHA256),
|
||||
);
|
||||
|
||||
stream::copy(file, &mut writer, cancel_signal)?;
|
||||
@@ -1371,6 +1517,7 @@ pub fn patch_subcommand(cli: &PatchCli, cancel_signal: &AtomicBool) -> Result<()
|
||||
&boot_patchers,
|
||||
cli.skip_system_ota_cert,
|
||||
cli.clear_vbmeta_flags,
|
||||
cli.vabc_algo,
|
||||
cli.zip_mode,
|
||||
&key_avb,
|
||||
&key_ota,
|
||||
@@ -1492,13 +1639,12 @@ pub fn extract_subcommand(cli: &ExtractCli, cancel_signal: &AtomicBool) -> Resul
|
||||
|
||||
unique_images.extend(cli.extract.partition.iter().cloned());
|
||||
} else if !cli.extract.none {
|
||||
let images = RequiredImages::new(&header.manifest);
|
||||
let images = get_required_images(&header.manifest, RequiredFlags::SYSTEM)
|
||||
.into_iter()
|
||||
.filter(|(_, flags)| !cli.extract.boot_only || flags.contains(PartitionFlags::BOOT))
|
||||
.map(|(name, _)| name);
|
||||
|
||||
if cli.extract.boot_only {
|
||||
unique_images.extend(images.iter_boot().map(|n| n.to_owned()));
|
||||
} else {
|
||||
unique_images.extend(images.iter().map(|n| n.to_owned()));
|
||||
}
|
||||
unique_images.extend(images);
|
||||
}
|
||||
|
||||
if let Some(path) = &cli.cert_ota {
|
||||
@@ -1825,16 +1971,20 @@ pub fn verify_subcommand(cli: &VerifyCli, cancel_signal: &AtomicBool) -> Result<
|
||||
|
||||
info!("Checking recovery ramdisk's otacerts.zip");
|
||||
|
||||
let required_images = RequiredImages::new(&header.manifest);
|
||||
let boot_images =
|
||||
boot::load_boot_images(&required_images.iter_boot().collect::<Vec<_>>(), |name| {
|
||||
Ok(Box::new(
|
||||
temp_dir
|
||||
.open(format!("{name}.img"))
|
||||
.map(|f| PSeekFile::new(f.into_std()))?,
|
||||
))
|
||||
})
|
||||
.context("Failed to load all boot images")?;
|
||||
let required_images = get_required_images(&header.manifest, RequiredFlags::empty());
|
||||
let boot_image_names = required_images
|
||||
.iter()
|
||||
.filter(|(_, flags)| flags.contains(PartitionFlags::BOOT))
|
||||
.map(|(name, _)| name.as_str())
|
||||
.collect::<Vec<_>>();
|
||||
let boot_images = boot::load_boot_images(&boot_image_names, |name| {
|
||||
Ok(Box::new(
|
||||
temp_dir
|
||||
.open(format!("{name}.img"))
|
||||
.map(|f| PSeekFile::new(f.into_std()))?,
|
||||
))
|
||||
})
|
||||
.context("Failed to load all boot images")?;
|
||||
let targets = OtaCertPatcher::new(ota_cert.clone())
|
||||
.find_targets(&boot_images, cancel_signal)
|
||||
.context("Failed to find boot image containing otacerts.zip")?;
|
||||
@@ -2080,6 +2230,18 @@ pub struct PatchCli {
|
||||
#[arg(long, help_heading = HEADING_OTHER)]
|
||||
pub clear_vbmeta_flags: bool,
|
||||
|
||||
/// Override the virtual A/B CoW compression algorithm.
|
||||
///
|
||||
/// This will slow down the patching process because every dynamic partition
|
||||
/// needs to be extracted to recompute the CoW size estimate. However, if a
|
||||
/// faster algorithm is chosen, then OTA installation using an OTA updater
|
||||
/// app will be faster. This does not affect sideloading from recovery mode.
|
||||
///
|
||||
/// Note that selecting a newer algorithm will prevent upgrading from older
|
||||
/// Android versions before support for the algorithm was introduced.
|
||||
#[arg(long, value_name = "ALGO", help_heading = HEADING_OTHER)]
|
||||
pub vabc_algo: Option<VabcAlgo>,
|
||||
|
||||
/// Zip creation mode for the output OTA zip.
|
||||
///
|
||||
/// The streaming mode produces zip files that contain data descriptors.
|
||||
|
||||
@@ -10,10 +10,10 @@ use std::{
|
||||
sync::atomic::AtomicBool,
|
||||
};
|
||||
|
||||
use aws_lc_rs::digest::{Algorithm, Context};
|
||||
use bstr::ByteSlice;
|
||||
use num_bigint_dig::{ModInverse, ToBigInt};
|
||||
use num_traits::{Pow, ToPrimitive};
|
||||
use ring::digest::{Algorithm, Context};
|
||||
use rsa::{traits::PublicKeyParts, BigUint, RsaPublicKey};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
@@ -55,7 +55,7 @@ pub const HEADER_MAX_SIZE: u64 = 64 * 1024;
|
||||
///
|
||||
/// ```rust
|
||||
/// use avbroot::format::hashtree::HashTree;
|
||||
/// let size = HashTree::new(4096, &aws_lc_rs::digest::SHA256, b"")
|
||||
/// let size = HashTree::new(4096, &ring::digest::SHA256, b"")
|
||||
/// .compute_level_offsets(8 * 1024 * 1024 * 1024)
|
||||
/// .unwrap()
|
||||
/// .first()
|
||||
@@ -165,9 +165,9 @@ type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
pub(crate) fn digest_algorithm(name: &str, for_verify: bool) -> Result<&'static Algorithm> {
|
||||
match name {
|
||||
"sha1" if for_verify => Ok(&aws_lc_rs::digest::SHA1_FOR_LEGACY_USE_ONLY),
|
||||
"sha256" => Ok(&aws_lc_rs::digest::SHA256),
|
||||
"sha512" => Ok(&aws_lc_rs::digest::SHA512),
|
||||
"sha1" if for_verify => Ok(&ring::digest::SHA1_FOR_LEGACY_USE_ONLY),
|
||||
"sha256" => Ok(&ring::digest::SHA256),
|
||||
"sha512" => Ok(&ring::digest::SHA512),
|
||||
a => Err(Error::UnsupportedHashAlgorithm(a.to_owned())),
|
||||
}
|
||||
}
|
||||
@@ -905,7 +905,7 @@ impl HashDescriptor {
|
||||
reader: impl Read,
|
||||
for_verify: bool,
|
||||
cancel_signal: &AtomicBool,
|
||||
) -> Result<aws_lc_rs::digest::Digest> {
|
||||
) -> Result<ring::digest::Digest> {
|
||||
let algorithm = digest_algorithm(&self.hash_algorithm, for_verify)?;
|
||||
let mut context = Context::new(algorithm);
|
||||
context.update(&self.salt);
|
||||
|
||||
@@ -8,9 +8,9 @@ use std::{
|
||||
str::{self, Utf8Error},
|
||||
};
|
||||
|
||||
use aws_lc_rs::digest::Context;
|
||||
use bstr::ByteSlice;
|
||||
use num_traits::ToPrimitive;
|
||||
use ring::digest::Context;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
use zerocopy::{little_endian, FromBytes, IntoBytes};
|
||||
@@ -890,7 +890,7 @@ impl BootImageV3Through4 {
|
||||
/// image was successfully signed. Returns false if there's no vbmeta
|
||||
/// structure to sign in [`V4Extra::signature`].
|
||||
pub fn sign(&mut self, key: &RsaSigningKey) -> Result<bool> {
|
||||
let mut context = Context::new(&aws_lc_rs::digest::SHA256);
|
||||
let mut context = Context::new(&ring::digest::SHA256);
|
||||
let image_size;
|
||||
|
||||
if let Some(v4) = &self.v4_extra {
|
||||
|
||||
@@ -707,7 +707,7 @@ impl FecImage {
|
||||
let fec_size: u32 =
|
||||
util::try_cast(self.fec.len()).map_err(|e| Error::IntOutOfBounds("fec_size", e))?;
|
||||
|
||||
let digest = aws_lc_rs::digest::digest(&aws_lc_rs::digest::SHA256, &self.fec);
|
||||
let digest = ring::digest::digest(&ring::digest::SHA256, &self.fec);
|
||||
|
||||
let header = RawHeader {
|
||||
magic: FEC_MAGIC.into(),
|
||||
@@ -781,7 +781,7 @@ impl<R: Read> FromReader<R> for FecImage {
|
||||
|
||||
let data_size = header.data_size.get();
|
||||
|
||||
let actual_digest = aws_lc_rs::digest::digest(&aws_lc_rs::digest::SHA256, &fec[..fec_size]);
|
||||
let actual_digest = ring::digest::digest(&ring::digest::SHA256, &fec[..fec_size]);
|
||||
if header.digest != actual_digest.as_ref() {
|
||||
return Err(Error::InvalidFecDigest {
|
||||
expected: hex::encode(header.digest),
|
||||
@@ -886,7 +886,7 @@ mod tests {
|
||||
let mut buf = vec![0u8; size];
|
||||
rand::thread_rng().fill_bytes(&mut buf);
|
||||
file.write_all(&buf).unwrap();
|
||||
aws_lc_rs::digest::digest(&aws_lc_rs::digest::SHA256, &buf)
|
||||
ring::digest::digest(&ring::digest::SHA256, &buf)
|
||||
};
|
||||
|
||||
let fec = Fec::new(size as u64, block_size, parity).unwrap();
|
||||
@@ -921,7 +921,7 @@ mod tests {
|
||||
let mut buf = Vec::new();
|
||||
file.rewind().unwrap();
|
||||
file.read_to_end(&mut buf).unwrap();
|
||||
aws_lc_rs::digest::digest(&aws_lc_rs::digest::SHA256, &buf)
|
||||
ring::digest::digest(&ring::digest::SHA256, &buf)
|
||||
};
|
||||
assert_eq!(repaired_digest.as_ref(), orig_digest.as_ref());
|
||||
|
||||
|
||||
@@ -9,12 +9,12 @@ use std::{
|
||||
sync::atomic::AtomicBool,
|
||||
};
|
||||
|
||||
use aws_lc_rs::digest::{Algorithm, Context};
|
||||
use bstr::ByteSlice;
|
||||
use rayon::{
|
||||
iter::{IndexedParallelIterator, ParallelIterator},
|
||||
slice::ParallelSliceMut,
|
||||
};
|
||||
use ring::digest::{Algorithm, Context};
|
||||
use thiserror::Error;
|
||||
use zerocopy::{little_endian, FromBytes, IntoBytes};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
|
||||
@@ -416,8 +416,8 @@ impl HashTree {
|
||||
if hash_tree_data != actual_hash_tree_data {
|
||||
// These are multiple megabytes, so only report the hashes.
|
||||
let algorithm = self.salted_context.algorithm();
|
||||
let expected = aws_lc_rs::digest::digest(algorithm, hash_tree_data);
|
||||
let actual = aws_lc_rs::digest::digest(algorithm, &actual_hash_tree_data);
|
||||
let expected = ring::digest::digest(algorithm, hash_tree_data);
|
||||
let actual = ring::digest::digest(algorithm, &actual_hash_tree_data);
|
||||
|
||||
return Err(Error::InvalidHashTree {
|
||||
expected: hex::encode(expected),
|
||||
@@ -662,7 +662,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn calculate_level_ranges() {
|
||||
let hash_tree = HashTree::new(4096, &aws_lc_rs::digest::SHA256, &[]);
|
||||
let hash_tree = HashTree::new(4096, &ring::digest::SHA256, &[]);
|
||||
assert_eq!(
|
||||
hash_tree.compute_level_offsets(0).unwrap(),
|
||||
&[] as &[Range<usize>],
|
||||
@@ -675,7 +675,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn blocks_for_ranges() {
|
||||
let hash_tree = HashTree::new(4096, &aws_lc_rs::digest::SHA256, b"Salt");
|
||||
let hash_tree = HashTree::new(4096, &ring::digest::SHA256, b"Salt");
|
||||
assert_eq!(
|
||||
hash_tree.blocks_for_ranges(16384, &[0..16384]).unwrap(),
|
||||
&[0..4],
|
||||
@@ -696,7 +696,7 @@ mod tests {
|
||||
#[test]
|
||||
fn generate_update_verify() {
|
||||
let cancel_signal = AtomicBool::new(false);
|
||||
let hash_tree = HashTree::new(64, &aws_lc_rs::digest::SHA256, b"Salt");
|
||||
let hash_tree = HashTree::new(64, &ring::digest::SHA256, b"Salt");
|
||||
let mut input = SharedCursor::new();
|
||||
|
||||
// Try input smaller than one block.
|
||||
|
||||
@@ -301,7 +301,7 @@ impl RawGeometry {
|
||||
let mut copy = *self;
|
||||
copy.checksum.fill(0);
|
||||
|
||||
let digest = aws_lc_rs::digest::digest(&aws_lc_rs::digest::SHA256, copy.as_bytes());
|
||||
let digest = ring::digest::digest(&ring::digest::SHA256, copy.as_bytes());
|
||||
if digest.as_ref() != self.checksum {
|
||||
return Err(Error::GeometryInvalidDigest {
|
||||
expected: hex::encode(self.checksum),
|
||||
@@ -517,7 +517,7 @@ impl RawHeader {
|
||||
|
||||
let portion = ©.as_bytes()[..expected_size];
|
||||
|
||||
let digest = aws_lc_rs::digest::digest(&aws_lc_rs::digest::SHA256, portion);
|
||||
let digest = ring::digest::digest(&ring::digest::SHA256, portion);
|
||||
if digest.as_ref() != self.header_checksum {
|
||||
return Err(Error::HeaderInvalidDigest {
|
||||
expected: hex::encode(self.header_checksum),
|
||||
@@ -1179,7 +1179,7 @@ impl RawMetadata {
|
||||
for slot in &self.slots {
|
||||
#[cfg(not(fuzzing))]
|
||||
{
|
||||
let mut context = aws_lc_rs::digest::Context::new(&aws_lc_rs::digest::SHA256);
|
||||
let mut context = ring::digest::Context::new(&ring::digest::SHA256);
|
||||
context.update(slot.partitions.as_bytes());
|
||||
context.update(slot.extents.as_bytes());
|
||||
context.update(slot.groups.as_bytes());
|
||||
@@ -1849,7 +1849,7 @@ impl TryFrom<&MetadataSlot> for RawMetadataSlot {
|
||||
raw_slot.header.tables_size = offset.into();
|
||||
|
||||
let tables_digest = {
|
||||
let mut context = aws_lc_rs::digest::Context::new(&aws_lc_rs::digest::SHA256);
|
||||
let mut context = ring::digest::Context::new(&ring::digest::SHA256);
|
||||
context.update(raw_slot.partitions.as_bytes());
|
||||
context.update(raw_slot.extents.as_bytes());
|
||||
context.update(raw_slot.groups.as_bytes());
|
||||
@@ -1861,8 +1861,8 @@ impl TryFrom<&MetadataSlot> for RawMetadataSlot {
|
||||
.tables_checksum
|
||||
.copy_from_slice(tables_digest.as_ref());
|
||||
|
||||
let header_digest = aws_lc_rs::digest::digest(
|
||||
&aws_lc_rs::digest::SHA256,
|
||||
let header_digest = ring::digest::digest(
|
||||
&ring::digest::SHA256,
|
||||
&raw_slot.header.as_bytes()[..header_size],
|
||||
);
|
||||
raw_slot
|
||||
@@ -1951,7 +1951,7 @@ impl TryFrom<&Metadata> for RawMetadata {
|
||||
};
|
||||
|
||||
let geometry_digest =
|
||||
aws_lc_rs::digest::digest(&aws_lc_rs::digest::SHA256, raw_metadata.geometry.as_bytes());
|
||||
ring::digest::digest(&ring::digest::SHA256, raw_metadata.geometry.as_bytes());
|
||||
raw_metadata
|
||||
.geometry
|
||||
.checksum
|
||||
|
||||
@@ -10,12 +10,12 @@ use std::{
|
||||
sync::atomic::AtomicBool,
|
||||
};
|
||||
|
||||
use aws_lc_rs::digest::{Algorithm, Context};
|
||||
use clap::ValueEnum;
|
||||
use cms::signed_data::SignedData;
|
||||
use const_oid::{db::rfc5912, ObjectIdentifier};
|
||||
use memchr::memmem;
|
||||
use prost::Message;
|
||||
use ring::digest::{Algorithm, Context};
|
||||
use thiserror::Error;
|
||||
use x509_cert::{der::Encode, Certificate};
|
||||
use zip::{result::ZipError, write::FileOptions, CompressionMethod, ZipArchive, ZipWriter};
|
||||
@@ -627,13 +627,10 @@ impl TryFrom<RawOtaSignature> for OtaSignature {
|
||||
|
||||
// We support SHA1 for verification only.
|
||||
let (digest_algo, sig_algo) = if signer.digest_alg.oid == rfc5912::ID_SHA_256 {
|
||||
(
|
||||
&aws_lc_rs::digest::SHA256,
|
||||
SignatureAlgorithm::Sha256WithRsa,
|
||||
)
|
||||
(&ring::digest::SHA256, SignatureAlgorithm::Sha256WithRsa)
|
||||
} else {
|
||||
(
|
||||
&aws_lc_rs::digest::SHA1_FOR_LEGACY_USE_ONLY,
|
||||
&ring::digest::SHA1_FOR_LEGACY_USE_ONLY,
|
||||
SignatureAlgorithm::Sha1WithRsa,
|
||||
)
|
||||
};
|
||||
@@ -831,7 +828,7 @@ fn validate_eocd(eocd: &[u8]) -> Result<()> {
|
||||
fn compute_signature_comment(
|
||||
key: &RsaSigningKey,
|
||||
cert: &Certificate,
|
||||
digest: aws_lc_rs::digest::Digest,
|
||||
digest: ring::digest::Digest,
|
||||
) -> Result<Vec<u8>> {
|
||||
let cms_signature =
|
||||
crypto::cms_sign_external(key, cert, digest.as_ref()).map_err(Error::CmsSign)?;
|
||||
@@ -883,7 +880,7 @@ pub struct StreamingSigningWriter<W> {
|
||||
impl<W: Write> StreamingSigningWriter<W> {
|
||||
pub fn new(inner: W) -> Self {
|
||||
Self {
|
||||
inner: HashingWriter::new(inner, Context::new(&aws_lc_rs::digest::SHA256)),
|
||||
inner: HashingWriter::new(inner, Context::new(&ring::digest::SHA256)),
|
||||
queue: Default::default(),
|
||||
used: 0,
|
||||
}
|
||||
@@ -987,7 +984,7 @@ impl<W: Read + Write + Seek> SeekableSigningWriter<W> {
|
||||
// Compute the digest of everything up until the comment size field.
|
||||
let mut hashing_writer = HashingWriter::new(
|
||||
io::sink(),
|
||||
aws_lc_rs::digest::Context::new(&aws_lc_rs::digest::SHA256),
|
||||
ring::digest::Context::new(&ring::digest::SHA256),
|
||||
);
|
||||
|
||||
self.rewind().map_err(|e| Error::DataRead("raw_data", e))?;
|
||||
|
||||
+121
-55
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2022-2024 Andrew Gunnerson
|
||||
// SPDX-FileCopyrightText: 2022-2025 Andrew Gunnerson
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use std::{
|
||||
@@ -9,10 +9,10 @@ use std::{
|
||||
sync::atomic::AtomicBool,
|
||||
};
|
||||
|
||||
use aws_lc_rs::digest::{Context, Digest};
|
||||
use base64::engine::general_purpose::STANDARD;
|
||||
use base64::Engine;
|
||||
use bzip2::write::BzDecoder;
|
||||
use clap::ValueEnum;
|
||||
use flate2::{write::GzEncoder, Compression};
|
||||
use liblzma::{
|
||||
stream::{Check, Stream},
|
||||
@@ -24,6 +24,7 @@ use rayon::{
|
||||
iter::{IndexedParallelIterator, IntoParallelRefMutIterator},
|
||||
prelude::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator},
|
||||
};
|
||||
use ring::digest::{Context, Digest};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
use x509_cert::Certificate;
|
||||
@@ -48,6 +49,9 @@ const PAYLOAD_VERSION: u64 = 2;
|
||||
|
||||
const MANIFEST_MAX_SIZE: usize = 4 * 1024 * 1024;
|
||||
|
||||
/// Size of each extent. This matches what AOSP's delta_generator does.
|
||||
const CHUNK_SIZE: u64 = 2 * 1024 * 1024;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
#[error("Unknown magic: {0:?}")]
|
||||
@@ -374,7 +378,7 @@ impl<W: Write> PayloadWriter<W> {
|
||||
// Get the length of an dummy signature struct since the length fields
|
||||
// are part of the data to be signed.
|
||||
let dummy_sig = sign_digest(
|
||||
aws_lc_rs::digest::digest(&aws_lc_rs::digest::SHA256, b"").as_ref(),
|
||||
ring::digest::digest(&ring::digest::SHA256, b"").as_ref(),
|
||||
&key,
|
||||
)?;
|
||||
let dummy_sig_size = dummy_sig.encoded_len();
|
||||
@@ -387,9 +391,9 @@ impl<W: Write> PayloadWriter<W> {
|
||||
let manifest_raw_new = header.manifest.encode_to_vec();
|
||||
|
||||
// Excludes signatures (hashes are for signing).
|
||||
let mut h_partial = Context::new(&aws_lc_rs::digest::SHA256);
|
||||
let mut h_partial = Context::new(&ring::digest::SHA256);
|
||||
// Includes signatures (hashes are for properties file).
|
||||
let mut h_full = Context::new(&aws_lc_rs::digest::SHA256);
|
||||
let mut h_full = Context::new(&ring::digest::SHA256);
|
||||
|
||||
// Write header to output file.
|
||||
let raw_header = RawHeader {
|
||||
@@ -600,9 +604,9 @@ pub fn verify_payload(
|
||||
.ok_or(Error::MissingField("signatures_size"))?;
|
||||
|
||||
// Excludes signatures (hashes are for signing).
|
||||
let mut h_partial = Context::new(&aws_lc_rs::digest::SHA256);
|
||||
let mut h_partial = Context::new(&ring::digest::SHA256);
|
||||
// Includes signatures (hashes are for properties file).
|
||||
let mut h_full = Context::new(&aws_lc_rs::digest::SHA256);
|
||||
let mut h_full = Context::new(&ring::digest::SHA256);
|
||||
|
||||
// Read from the beginning to the metadata signature.
|
||||
let metadata_size = header.blob_offset - u64::from(header.metadata_signature_size);
|
||||
@@ -756,7 +760,7 @@ pub fn apply_operation(
|
||||
|
||||
writer.seek(SeekFrom::Start(out_offset)).map_err(error_fn)?;
|
||||
|
||||
let mut hasher = Context::new(&aws_lc_rs::digest::SHA256);
|
||||
let mut hasher = Context::new(&ring::digest::SHA256);
|
||||
|
||||
match op.r#type() {
|
||||
// Handle ZERO/DISCARD specially since they don't require access to
|
||||
@@ -925,7 +929,7 @@ pub fn extract_images<'a>(
|
||||
fn compress_chunk(raw_data: &[u8], cancel_signal: &AtomicBool) -> Result<(Vec<u8>, Digest)> {
|
||||
let reader = Cursor::new(raw_data);
|
||||
let writer = Cursor::new(Vec::new());
|
||||
let hashing_writer = HashingWriter::new(writer, Context::new(&aws_lc_rs::digest::SHA256));
|
||||
let hashing_writer = HashingWriter::new(writer, Context::new(&ring::digest::SHA256));
|
||||
|
||||
// AOSP's payload_consumer does not support checking CRC during
|
||||
// decompression. Also, we intentionally pick the lowest compression level
|
||||
@@ -945,21 +949,13 @@ fn compress_chunk(raw_data: &[u8], cancel_signal: &AtomicBool) -> Result<(Vec<u8
|
||||
Ok((data, digest_compressed))
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize, ValueEnum)]
|
||||
pub enum VabcAlgo {
|
||||
Lz4,
|
||||
Gzip,
|
||||
Gz,
|
||||
}
|
||||
|
||||
impl VabcAlgo {
|
||||
pub fn new(name: &str) -> Option<Self> {
|
||||
match name {
|
||||
"lz4" => Some(Self::Lz4),
|
||||
"gz" => Some(Self::Gzip),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn compressed_size(self, mut raw_data: &[u8], block_size: u32) -> Result<u64> {
|
||||
let mut total = 0;
|
||||
|
||||
@@ -971,7 +967,7 @@ impl VabcAlgo {
|
||||
// AOSP's libsnapshot.
|
||||
let compressed = match self {
|
||||
Self::Lz4 => lz4_flex::block::compress(chunk),
|
||||
Self::Gzip => {
|
||||
Self::Gz => {
|
||||
let mut encoder = GzEncoder::new(Vec::new(), Compression::best());
|
||||
encoder.write_all(chunk).map_err(Error::GzCompress)?;
|
||||
encoder.finish().map_err(Error::GzCompress)?
|
||||
@@ -989,13 +985,100 @@ impl VabcAlgo {
|
||||
|
||||
impl fmt::Display for VabcAlgo {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Lz4 => f.write_str("lz4"),
|
||||
Self::Gzip => f.write_str("gz"),
|
||||
}
|
||||
f.write_str(self.to_possible_value().ok_or(fmt::Error)?.get_name())
|
||||
}
|
||||
}
|
||||
|
||||
/// Add fudge factor to CoW estimate to account for overhead.
|
||||
fn fudge_cow_estimate(mut estimate: u64) -> Option<u64> {
|
||||
// lz4_flex and zlib-rs usually compress better than the lz4 and zlib
|
||||
// implementations used by libsnapshot_cow. Make up for this by adding
|
||||
// percentage-based overhead.
|
||||
estimate = estimate.checked_add(estimate / 100)?;
|
||||
|
||||
// We also need to account for constant overhead, especially with smaller
|
||||
// partitions. We can match what delta_generator normally adds in
|
||||
// CowWriterV2::InitPos() exactly. Since we only ever create full OTAs, we
|
||||
// can assume that all CoW operations are kCowReplaceOp.
|
||||
|
||||
// sizeof(CowHeader).
|
||||
estimate = estimate.checked_add(38)?;
|
||||
// header_.buffer_size (equal to BUFFER_REGION_DEFAULT_SIZE).
|
||||
estimate = estimate.checked_add(2 * 1024 * 1024)?;
|
||||
// CowOptions::cluster_ops * sizeof(CowOperationV2).
|
||||
estimate = estimate.checked_add(200 * 20)?;
|
||||
|
||||
Some(estimate)
|
||||
}
|
||||
|
||||
/// Compute the VABC CoW v2 size estimate. The caller must update
|
||||
/// [`PartitionUpdate::estimate_cow_size`] with this value or else update_engine
|
||||
/// may fail to flash the partition due to running out of space on the CoW block
|
||||
/// device. CoW v2 + other algorithms and also CoW v3 are currently unsupported
|
||||
/// because there currently are no known OTAs that use those configurations.
|
||||
pub fn compute_cow_estimate(
|
||||
input: &(dyn ReadSeekReopen + Sync),
|
||||
partition_name: &str,
|
||||
block_size: u32,
|
||||
vabc_algo: VabcAlgo,
|
||||
cancel_signal: &AtomicBool,
|
||||
) -> Result<u64> {
|
||||
let file_size = input
|
||||
.reopen_boxed()
|
||||
.and_then(|mut r| r.seek(SeekFrom::End(0)))
|
||||
.map_err(|e| Error::InputOpen(partition_name.to_owned(), e))?;
|
||||
let final_chunk_different = file_size % CHUNK_SIZE != 0;
|
||||
|
||||
if file_size % u64::from(block_size) != 0 || CHUNK_SIZE % u64::from(block_size) != 0 {
|
||||
return Err(Error::InvalidPartitionSize {
|
||||
name: partition_name.to_owned(),
|
||||
size: file_size,
|
||||
block_size,
|
||||
});
|
||||
}
|
||||
|
||||
let chunks_total = file_size.div_ceil(CHUNK_SIZE);
|
||||
|
||||
let cow_estimate = (0..chunks_total)
|
||||
.into_par_iter()
|
||||
.map(|chunk| -> Result<u64> {
|
||||
let data = (|| {
|
||||
let mut reader = input.reopen_boxed()?;
|
||||
reader.seek(SeekFrom::Start(chunk * CHUNK_SIZE))?;
|
||||
|
||||
let chunk_size = if final_chunk_different && chunk == chunks_total - 1 {
|
||||
file_size % CHUNK_SIZE
|
||||
} else {
|
||||
CHUNK_SIZE
|
||||
};
|
||||
|
||||
stream::check_cancel(cancel_signal)?;
|
||||
reader.read_vec_exact(chunk_size as usize)
|
||||
})()
|
||||
.map_err(Error::ChunkRead)?;
|
||||
|
||||
vabc_algo.compressed_size(&data, block_size)
|
||||
})
|
||||
.try_fold(
|
||||
|| 0u64,
|
||||
|total, chunk_estimate| -> Result<u64> {
|
||||
total
|
||||
.checked_add(chunk_estimate?)
|
||||
.ok_or(Error::IntOverflow("cow_estimate"))
|
||||
},
|
||||
)
|
||||
.try_reduce(
|
||||
|| 0u64,
|
||||
|total, partial| {
|
||||
total
|
||||
.checked_add(partial)
|
||||
.ok_or(Error::IntOverflow("cow_estimate"))
|
||||
},
|
||||
)?;
|
||||
|
||||
fudge_cow_estimate(cow_estimate).ok_or(Error::IntOverflow("cow_estimate_fudged"))
|
||||
}
|
||||
|
||||
/// Compress the image and return the corresponding information to insert into
|
||||
/// the payload manifest's [`PartitionUpdate`] instance. The uncompressed data
|
||||
/// is split into 2 MiB chunks, which are read and compressed in parallel, and
|
||||
@@ -1004,12 +1087,9 @@ impl fmt::Display for VabcAlgo {
|
||||
/// update [`InstallOperation::data_offset`] in each operation manually because
|
||||
/// the initial values are relative to 0.
|
||||
///
|
||||
/// If `vabc_algo` is set, the VABC CoW v2 size estimate will be computed. The
|
||||
/// caller must update [`PartitionUpdate::estimate_cow_size`] with this value or
|
||||
/// else update_engine may fail to flash the partition due to running out of
|
||||
/// space on the CoW block device. CoW v2 + other algorithms and also CoW v3 are
|
||||
/// currently unsupported because there currently are no known OTAs that use
|
||||
/// those configurations.
|
||||
/// If `vabc_algo` is set, the VABC CoW size estimate will also be computed.
|
||||
/// This is more efficient than separately calling [`compute_cow_estimate`]
|
||||
/// since the input does not need to be read twice.
|
||||
pub fn compress_image(
|
||||
input: &(dyn ReadSeekReopen + Sync),
|
||||
output: &(dyn WriteSeekReopen + Sync),
|
||||
@@ -1018,7 +1098,6 @@ pub fn compress_image(
|
||||
vabc_algo: Option<VabcAlgo>,
|
||||
cancel_signal: &AtomicBool,
|
||||
) -> Result<(PartitionInfo, Vec<InstallOperation>, Option<u64>)> {
|
||||
const CHUNK_SIZE: u64 = 2 * 1024 * 1024;
|
||||
const CHUNK_GROUP: u64 = 32;
|
||||
|
||||
let file_size = input
|
||||
@@ -1036,9 +1115,9 @@ pub fn compress_image(
|
||||
}
|
||||
|
||||
let chunks_total = file_size.div_ceil(CHUNK_SIZE);
|
||||
let mut bytes_compressed = 0;
|
||||
let mut context_uncompressed = Context::new(&aws_lc_rs::digest::SHA256);
|
||||
let mut cow_estimate = 0;
|
||||
let mut bytes_compressed = 0u64;
|
||||
let mut context_uncompressed = Context::new(&ring::digest::SHA256);
|
||||
let mut cow_estimate = 0u64;
|
||||
let mut operations = vec![];
|
||||
|
||||
// Read the file one group at a time. This allows for some parallelization
|
||||
@@ -1100,8 +1179,12 @@ pub fn compress_image(
|
||||
|
||||
for (data, operation, cow_size) in &mut compressed_data_group {
|
||||
operation.data_offset = Some(bytes_compressed);
|
||||
bytes_compressed += data.len() as u64;
|
||||
cow_estimate += *cow_size;
|
||||
bytes_compressed = bytes_compressed
|
||||
.checked_add(data.len() as u64)
|
||||
.ok_or(Error::IntOverflow("bytes_compressed"))?;
|
||||
cow_estimate = cow_estimate
|
||||
.checked_add(*cow_size)
|
||||
.ok_or(Error::IntOverflow("cow_estimate"))?;
|
||||
}
|
||||
|
||||
let group_operations = compressed_data_group
|
||||
@@ -1126,24 +1209,7 @@ pub fn compress_image(
|
||||
};
|
||||
|
||||
let cow_estimate = if vabc_algo.is_some() {
|
||||
// lz4_flex and miniz_oxide usually compress better than the lz4 and
|
||||
// zlib implementations used by libsnapshot_cow. Make up for this by
|
||||
// adding percentage-based overhead.
|
||||
cow_estimate += cow_estimate / 100;
|
||||
|
||||
// We also need to account for constant overhead, especially with
|
||||
// smaller partitions. We can match what delta_generator normally adds
|
||||
// in CowWriterV2::InitPos() exactly. Since we only ever create full
|
||||
// OTAs, we can assume that all CoW operations are kCowReplaceOp.
|
||||
|
||||
// sizeof(CowHeader).
|
||||
cow_estimate += 38;
|
||||
// header_.buffer_size (equal to BUFFER_REGION_DEFAULT_SIZE).
|
||||
cow_estimate += 2 * 1024 * 1024;
|
||||
// CowOptions::cluster_ops * sizeof(CowOperationV2).
|
||||
cow_estimate += 200 * 20;
|
||||
|
||||
Some(cow_estimate)
|
||||
Some(fudge_cow_estimate(cow_estimate).ok_or(Error::IntOverflow("cow_estimate_fudged"))?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -1208,7 +1274,7 @@ pub fn compress_modified_image(
|
||||
|
||||
let groups_total = operations.len().div_ceil(OPERATION_GROUP);
|
||||
let mut bytes_compressed = 0;
|
||||
let mut context_uncompressed = Context::new(&aws_lc_rs::digest::SHA256);
|
||||
let mut context_uncompressed = Context::new(&ring::digest::SHA256);
|
||||
let mut modified_operations = vec![];
|
||||
|
||||
// Read the file one group at a time. This allows for some parallelization
|
||||
|
||||
@@ -14,7 +14,6 @@ use std::{
|
||||
sync::atomic::AtomicBool,
|
||||
};
|
||||
|
||||
use aws_lc_rs::digest::Context;
|
||||
use bstr::ByteSlice;
|
||||
use liblzma::{
|
||||
stream::{Check, Stream},
|
||||
@@ -22,6 +21,7 @@ use liblzma::{
|
||||
};
|
||||
use rayon::iter::{IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator};
|
||||
use regex::bytes::Regex;
|
||||
use ring::digest::Context;
|
||||
use rsa::RsaPublicKey;
|
||||
use thiserror::Error;
|
||||
use tracing::{debug, debug_span, trace, warn, Span};
|
||||
@@ -1180,7 +1180,7 @@ fn save_boot_image(
|
||||
};
|
||||
|
||||
// Write new boot image. We reuse the existing salt for the digest.
|
||||
let mut context = Context::new(&aws_lc_rs::digest::SHA256);
|
||||
let mut context = Context::new(&ring::digest::SHA256);
|
||||
context.update(&descriptor.salt);
|
||||
let mut hashing_writer = HashingWriter::new(writer, context);
|
||||
info.boot_image
|
||||
|
||||
@@ -10,8 +10,8 @@ use std::{
|
||||
},
|
||||
};
|
||||
|
||||
use aws_lc_rs::digest::Context;
|
||||
use num_traits::ToPrimitive;
|
||||
use ring::digest::Context;
|
||||
|
||||
use crate::util;
|
||||
|
||||
@@ -637,7 +637,7 @@ mod tests {
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
};
|
||||
|
||||
use aws_lc_rs::digest::Context;
|
||||
use ring::digest::Context;
|
||||
|
||||
use super::{
|
||||
CountingReader, CountingWriter, HashingReader, HashingWriter, PSeekFile, ReadDiscardExt,
|
||||
@@ -713,7 +713,7 @@ mod tests {
|
||||
#[test]
|
||||
fn hashing_reader() {
|
||||
let raw_reader = Cursor::new(b"foobar");
|
||||
let mut reader = HashingReader::new(raw_reader, Context::new(&aws_lc_rs::digest::SHA256));
|
||||
let mut reader = HashingReader::new(raw_reader, Context::new(&ring::digest::SHA256));
|
||||
|
||||
let mut buf = [0u8; 6];
|
||||
reader.read_exact(&mut buf[..0]).unwrap();
|
||||
@@ -730,7 +730,7 @@ mod tests {
|
||||
#[test]
|
||||
fn hashing_writer() {
|
||||
let raw_writer = Cursor::new([0u8; 6]);
|
||||
let mut writer = HashingWriter::new(raw_writer, Context::new(&aws_lc_rs::digest::SHA256));
|
||||
let mut writer = HashingWriter::new(raw_writer, Context::new(&ring::digest::SHA256));
|
||||
|
||||
writer.write_all(b"").unwrap();
|
||||
writer.write_all(b"foo").unwrap();
|
||||
|
||||
@@ -134,7 +134,7 @@ fn round_trip_root_image() {
|
||||
|
||||
// Verify checksum of the output.
|
||||
assert_eq!(
|
||||
aws_lc_rs::digest::digest(&aws_lc_rs::digest::SHA512, &data).as_ref(),
|
||||
ring::digest::digest(&ring::digest::SHA512, &data).as_ref(),
|
||||
[
|
||||
0x3b, 0x01, 0xf6, 0x04, 0x04, 0x6e, 0x6f, 0x60, 0x9c, 0xb0, 0x8b, 0x8a, 0x43, 0xf7,
|
||||
0x91, 0x2e, 0xc4, 0x1b, 0xc0, 0x7f, 0xa1, 0xe4, 0xe6, 0x59, 0x14, 0x08, 0xbe, 0x83,
|
||||
@@ -233,7 +233,7 @@ fn round_trip_appended_hash_image() {
|
||||
|
||||
// Verify checksum of the output.
|
||||
assert_eq!(
|
||||
aws_lc_rs::digest::digest(&aws_lc_rs::digest::SHA512, &data).as_ref(),
|
||||
ring::digest::digest(&ring::digest::SHA512, &data).as_ref(),
|
||||
[
|
||||
0x91, 0x38, 0x61, 0xc0, 0x68, 0x2a, 0x8b, 0xd8, 0x01, 0xa6, 0xe4, 0x4c, 0x1d, 0x27,
|
||||
0x93, 0x1b, 0xa4, 0x63, 0xd1, 0xbb, 0xf1, 0x64, 0x05, 0xf2, 0xa1, 0xa0, 0xb3, 0x35,
|
||||
@@ -341,7 +341,7 @@ fn round_trip_appended_hash_tree_image_fixed_size() {
|
||||
|
||||
// Verify checksum of the output.
|
||||
assert_eq!(
|
||||
aws_lc_rs::digest::digest(&aws_lc_rs::digest::SHA512, &data).as_ref(),
|
||||
ring::digest::digest(&ring::digest::SHA512, &data).as_ref(),
|
||||
[
|
||||
0x92, 0xdd, 0x4d, 0xc5, 0xb0, 0x5b, 0x4f, 0x65, 0x97, 0x5a, 0x72, 0x66, 0xde, 0x82,
|
||||
0xc2, 0x2f, 0x33, 0x86, 0x8b, 0x65, 0x67, 0x80, 0x1d, 0xca, 0xd6, 0x2c, 0xfc, 0xca,
|
||||
@@ -448,7 +448,7 @@ fn round_trip_appended_hash_tree_image_minimum_size() {
|
||||
|
||||
// Verify checksum of the output.
|
||||
assert_eq!(
|
||||
aws_lc_rs::digest::digest(&aws_lc_rs::digest::SHA512, &data).as_ref(),
|
||||
ring::digest::digest(&ring::digest::SHA512, &data).as_ref(),
|
||||
[
|
||||
0xcf, 0x6b, 0x90, 0xcf, 0x77, 0x76, 0x62, 0x12, 0xc2, 0x22, 0xe6, 0xd5, 0x5b, 0xab,
|
||||
0x82, 0xd8, 0x6c, 0x93, 0xa3, 0x35, 0x5b, 0x77, 0xe0, 0x38, 0x12, 0x48, 0x90, 0x0c,
|
||||
|
||||
@@ -49,7 +49,7 @@ fn round_trip(image: &BootImage, sha512: &[u8; 64], expected_version: u32) {
|
||||
let data = writer.into_inner();
|
||||
|
||||
assert_eq!(
|
||||
aws_lc_rs::digest::digest(&aws_lc_rs::digest::SHA512, &data).as_ref(),
|
||||
ring::digest::digest(&ring::digest::SHA512, &data).as_ref(),
|
||||
sha512,
|
||||
);
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ fn generate_archive() -> Vec<u8> {
|
||||
let data = writer.into_inner();
|
||||
|
||||
assert_eq!(
|
||||
aws_lc_rs::digest::digest(&aws_lc_rs::digest::SHA512, &data).as_ref(),
|
||||
ring::digest::digest(&ring::digest::SHA512, &data).as_ref(),
|
||||
[
|
||||
0xb0, 0x51, 0xac, 0x28, 0x6f, 0x78, 0xe2, 0xe7, 0x45, 0xa0, 0x52, 0x7c, 0xff, 0x42,
|
||||
0x30, 0x55, 0xbd, 0x64, 0x7d, 0x4e, 0xb8, 0xe6, 0x95, 0xe5, 0x9b, 0xd1, 0x13, 0xd6,
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ fn round_trip(metadata: &Metadata, sha512: &[u8; 64]) {
|
||||
let data = writer.into_inner();
|
||||
|
||||
assert_eq!(
|
||||
aws_lc_rs::digest::digest(&aws_lc_rs::digest::SHA512, &data).as_ref(),
|
||||
ring::digest::digest(&ring::digest::SHA512, &data).as_ref(),
|
||||
sha512,
|
||||
);
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ fn round_trip(block_size: u32, crc32: u32, test_chunks: &[TestChunk], sha512: &[
|
||||
let data = writer.into_inner();
|
||||
|
||||
assert_eq!(
|
||||
aws_lc_rs::digest::digest(&aws_lc_rs::digest::SHA512, &data).as_ref(),
|
||||
ring::digest::digest(&ring::digest::SHA512, &data).as_ref(),
|
||||
sha512,
|
||||
);
|
||||
|
||||
|
||||
@@ -37,11 +37,17 @@ allow = [
|
||||
"GPL-3.0",
|
||||
"ISC",
|
||||
"MIT",
|
||||
"OpenSSL",
|
||||
"Unicode-3.0",
|
||||
"Zlib",
|
||||
]
|
||||
|
||||
[[licenses.clarify]]
|
||||
name = "ring"
|
||||
expression = "MIT AND ISC AND OpenSSL"
|
||||
license-files = [
|
||||
{ path = "LICENSE", hash = 0xbd0eed23 },
|
||||
]
|
||||
|
||||
[bans]
|
||||
multiple-versions = "warn"
|
||||
multiple-versions-include-dev = true
|
||||
@@ -57,8 +63,6 @@ include-workspace = true
|
||||
bypass = [
|
||||
# Copies of unmodified crashwrangler objects for old macOS versions.
|
||||
{ name = "honggfuzz", allow-globs = ["honggfuzz/third_party/mac/CrashReport_*.o"] },
|
||||
# Only used in tests.
|
||||
{ name = "libloading", allow-globs = ["tests/*.dll"] }
|
||||
]
|
||||
|
||||
[sources]
|
||||
|
||||
+1
-1
@@ -9,12 +9,12 @@ publish = false
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
aws-lc-rs = { version = "1.0.0", default-features = false, features = ["aws-lc-sys"] }
|
||||
anyhow = "1.0.75"
|
||||
avbroot = { path = "../avbroot" }
|
||||
clap = { version = "4.4.1", features = ["derive"] }
|
||||
ctrlc = "3.4.0"
|
||||
hex = { version = "0.4.3", features = ["serde"] }
|
||||
ring = "0.17.14"
|
||||
rsa = { version = "0.9.6", features = ["hazmat"] }
|
||||
serde = { version = "1.0.188", features = ["derive"] }
|
||||
tempfile = "3.8.0"
|
||||
|
||||
+1
-1
@@ -143,7 +143,7 @@ patched = "27b80c7be9c1e527ea26abe3dabde245c580e6f26ec084204278fbfd81a39f83"
|
||||
# What's unique: boot (boot v2)
|
||||
|
||||
[profile.pixel_v2]
|
||||
vabc_algo = "Gzip"
|
||||
vabc_algo = "Gz"
|
||||
|
||||
[profile.pixel_v2.partitions.boot]
|
||||
avb.signed = false
|
||||
|
||||
+2
-2
@@ -69,7 +69,7 @@ fn hash_file(path: &Path, cancel_signal: &AtomicBool) -> Result<[u8; 32]> {
|
||||
let raw_reader =
|
||||
File::open(path).with_context(|| format!("Failed to open for reading: {path:?}"))?;
|
||||
let buf_reader = BufReader::new(raw_reader);
|
||||
let context = aws_lc_rs::digest::Context::new(&aws_lc_rs::digest::SHA256);
|
||||
let context = ring::digest::Context::new(&ring::digest::SHA256);
|
||||
let mut hashing_reader = HashingReader::new(buf_reader, context);
|
||||
|
||||
stream::copy(&mut hashing_reader, io::sink(), cancel_signal)?;
|
||||
@@ -104,7 +104,7 @@ fn append_avb(
|
||||
cancel_signal: &AtomicBool,
|
||||
) -> Result<()> {
|
||||
let image_size = file.seek(SeekFrom::End(0))?;
|
||||
let salt = aws_lc_rs::digest::digest(&aws_lc_rs::digest::SHA256, b"avbroot");
|
||||
let salt = ring::digest::digest(&ring::digest::SHA256, b"avbroot");
|
||||
let descriptors = vec![
|
||||
if hash_tree {
|
||||
let mut descriptor = HashTreeDescriptor {
|
||||
|
||||
Reference in New Issue
Block a user