ADFA-4676: Shield — verify rootfs download (size + SHA-256) before extraction#192
Merged
Merged
Conversation
Add an app-side integrity gate so an incomplete/corrupt/stale rootfs download
can never reach extraction. Previously the pipeline trusted aria2c's exit code
alone; an incomplete tarball (1,128,939,201 B vs the .meta4's 1,453,144,579 B)
passed and failed mid-extraction.
- MetalinkFile: pure parser for the .meta4 (RFC 5854) -> { fileName, size,
file-level SHA-256, mirrors }. Ignores the per-piece <hash> entries in <pieces>.
- DownloadVerifier: size check + streaming SHA-256; fail-closed.
- Aria2Manager: after exit 0, for Metalink downloads, verify downloads/<name>
against the .meta4 size + SHA-256. On mismatch: delete the artifact (+ .aria2)
and report onIntegrityFailure (new DownloadListener default method); on success
remove any stale sibling tarball, then report complete.
- InstallService: surface integrity failures with a dedicated message.
- Unit tests for MetalinkFile (incl. 'does not pick a piece hash') and
DownloadVerifier (OK / WRONG_SIZE / WRONG_HASH / MISSING).
…a4 fetch
Make the download robust to stop-and-restart and avoid redundant work:
- Fetch the .meta4 once up front; use it for the integrity gate, the --split
mirror count (via MetalinkSplit.splitForMirrorCount), and to reconcile what is
already on disk. Removes the second .meta4 fetch (resolveSplitFromMetalink).
- Before profiling/downloading, inspect downloads/<file>: if it is already the
full, SHA-256-verified artifact, skip the profiler + re-download and go
straight to onComplete; if it is complete-but-corrupt, oversized, or a partial
with no .aria2 control file, discard it so the run starts clean; a partial WITH
a control file is left for aria2 --continue to resume.
- This also fixes the network profiler tripping with errorCode=13 ("file exists
but a control file does not exist") when a completed download was left in place
after the user stopped mid-flow.
- Extract pruneStaleSiblings() and reuse the single MetalinkFile in the post-
download verification (no re-fetch).
Leverage the .meta4 per-piece SHA-256 hashes + aria2 --check-integrity to recover instead of re-downloading from scratch: - On (re)start, if downloads/<file> is the full verified artifact, reuse it and skip the download; if it is larger than the declared size, discard it (no piece map can match); otherwise (partial OR complete-but-corrupt) KEEP it and let the main aria2 run (--continue --allow-overwrite --check-integrity) salvage it, re-downloading only the damaged/missing 1 MiB pieces. - Skip the network profiler when resuming/repairing (it lacks --allow-overwrite/ --check-integrity and would trip errorCode=13 on a file without a control). - The whole-file SHA-256 gate still runs after the download; if repair still cannot produce a byte-perfect file it deletes the artifact and reports an integrity failure, so a full re-download is only the last resort. This stops throwing away a nearly-complete download (e.g. stopped at 95%) and uses the integrity infrastructure as intended.
- Treat a user-initiated stop as a clean cancellation, not a failure. Closing the aria2 stream via stopDownload() made readLine() throw and hit the generic catch, which logged 'Native Execution Error' and fired onError -> a spurious 'Download Failed'. Now, when isCancelled, route to a new no-op DownloadListener.onCancelled() (default method) instead: no ERROR log, no failure banner, no false analytics event. No new user-facing string. - Use the .aria2 control file as the 'in progress' signal in the on-disk reconciliation. aria2 pre-allocates the full size and keeps its control file while downloading, so length alone cannot distinguish 'complete' from 'in progress'. If the control file exists, resume/piece-repair without wasting a full-file SHA-256; only hash when there is no control file (to detect a genuinely complete artifact to reuse).
luisguzman-adfa
marked this pull request as ready for review
July 12, 2026 06:00
Collaborator
Author
|
On-device validation (forced stop/restart stress test), both tiers:
Note: the |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds an app-side integrity gate so an incomplete/corrupt/stale rootfs download can never reach extraction. Previously the pipeline trusted aria2c's exit code alone; an incomplete tarball (1,128,939,201 B vs the .meta4's 1,453,144,579 B) passed and then failed mid-extraction.
Changes
.meta4(RFC 5854) into{ fileName, size, file-level SHA-256, mirrors }. Takes the<hash type="sha-256">that is a direct child of<file>, not the per-piece hashes inside<pieces>.downloads/<file name>against the.meta4size + SHA-256. On mismatch: delete the artifact (+.aria2) and reportonIntegrityFailure(newDownloadListenerdefault method, so the other callers are unaffected); on success, remove any stale sibling tarball, then report complete.install_error_verify) instead of the generic "Download Failed".install_error_verifyadded tovalues/(en) + the 33 localizedstrings.xml.Verification
./gradlew testDebugUnitTest :app:lintDebug assembleDebug(compile + lint + unit tests).Follow-ups (same ticket)
aria2 --continue --check-integrity) before surfacing failure..meta4fetches (split + verify) into a single fetch.