diff options
Diffstat (limited to 'pw_software_update/public/pw_software_update/bundled_update_backend.h')
-rw-r--r-- | pw_software_update/public/pw_software_update/bundled_update_backend.h | 105 |
1 files changed, 96 insertions, 9 deletions
diff --git a/pw_software_update/public/pw_software_update/bundled_update_backend.h b/pw_software_update/public/pw_software_update/bundled_update_backend.h index 40b704a4b..ae80e065e 100644 --- a/pw_software_update/public/pw_software_update/bundled_update_backend.h +++ b/pw_software_update/public/pw_software_update/bundled_update_backend.h @@ -30,13 +30,17 @@ class BundledUpdateBackend { public: virtual ~BundledUpdateBackend() = default; - // Optionally verify that the instance/content of the target file in use - // on-device matches the metadata in the given manifest, called before apply. - // (e.g. by checksum, if failed abort partial update and wipe/mark-invalid - // running manifest) + // Perform optional, product-specific validations to the specified target + // file, using whatever metadata available in manifest. + // + // This is called for each target file after the standard verification has + // passed. virtual Status VerifyTargetFile( [[maybe_unused]] ManifestAccessor manifest, [[maybe_unused]] std::string_view target_file_name) { + // TODO(backend): Perform any additional product-specific validations. + // It is safe to assume the target's payload has passed standard + // verification. return OkStatus(); }; @@ -86,16 +90,99 @@ class BundledUpdateBackend { stream::Reader& target_payload, size_t update_bundle_offset) = 0; - // Get reader of the device's current manifest. + // Backend to probe the device manifest and prepare a ready-to-go reader + // for it. See the comments to `GetCurrentManfestReader()` for more context. + virtual Status BeforeManifestRead() { + // Todo(backend): + // 1. Probe device to see if a well-formed manifest already exists. + // 2. If not, return `Status::NotFound()`. Note this will cause + // anti-rollback to skip. So please don't always return + // `Status::NotFound()`! + // 3. If yes, instantiate and activate a reader for the manifest! + // 4. Return any unexpected condition as errors but note this will cause + // the current software update session to abort. + return OkStatus(); + } + + // Backend to provide a ready-to-go reader for the on-device manifest blob. + // This function is called after a successful `BeforeManifestRead()`, + // potentially more than once. + // + // This manifest blob is a serialized `message Manifest{...}` as defined in + // update_bundle.proto. + // + // This manifest blob is ALWAYS and EXCLUSIVELY persisted by a successful + // software update. Thus it may not available before the first software + // update, in which case `BeforeManifestRead()` should've returned + // `Status::NotFound()`. + // + // This manifest contains trusted metadata of all software currently running + // on the device and used for anti-rollback checks. It MUST NOT be tampered + // by factory resets, flashing, or any other means other than software + // updates. virtual Result<stream::SeekableReader*> GetCurrentManifestReader() { + // Todo(backend): + // 1. Double check if a ready-to-go reader has been prepared by + // `BeforeManifestRead()`. + // 2. If yes (expected), return the reader. + // 3. If not (unexpected), return `Status::FailedPrecondition()`. return Status::Unimplemented(); } - // Use a reader that provides a new manifest for the device to save. - virtual Status UpdateCurrentManifest( - [[maybe_unused]] stream::Reader& manifest) { + // TODO(alizhang): Deprecate GetCurrentManifestReader in favor of + // `GetManifestReader()`. + virtual Result<stream::SeekableReader*> GetManifestReader() { + return GetCurrentManifestReader(); + } + + // Backend to prepare for on-device manifest update, e.g. make necessary + // efforts to ready the manifest writer. The manifest writer is used to + // persist a new manifest on-device following a successful software update. + // Manifest writing is never mixed with reading (i.e. reader and writer are + // used sequentially). + virtual Status BeforeManifestWrite() { + // Todo(backend): + // 1. Instantiate and activate a manifest writer pointing at a persistent + // storage that at least could survive a factory data reset (FDR), if not + // tamper-resistant. return OkStatus(); - }; + } + + // Backend to provide a ready-to-go writer for the on-device manifest blob. + // This function is called after a successful `BeforeManifestWrite()`, + // potentially more than once. + // + // This manifest blob is a serialized `message Manifest{...}` as defined in + // update_bundle.proto. + // + // This manifest blob is ALWAYS and EXCLUSIVELY persisted by a successful + // software update. + // + // This manifest contains trusted metadata of all software currently running + // on the device and used for anti-rollback checks. It MUST NOT be tampered + // by factory resets, flashing, or any other means other than software + // updates. + virtual Result<stream::Writer*> GetManifestWriter() { + // Todo(backend): + // 1. Double check a writer is ready to go as result of + // `BeforeManifestWrite()`. + // 2. If yes (expected), simply return the writer. + // 3. If not (unexpected), return `Status::FailedPrecondition()`. + return Status::Unimplemented(); + } + + // Backend to finish up manifest writing. + virtual Status AfterManifestWrite() { + // Todo(backend): + // Protect the newly persisted manifest blob. This is to make manifest + // probing / reading easier and more reliable. This could involve taking + // a measurement (e.g. checksum) and storing that measurement in a + // FDR-safe tag, replicating the manifest in a backup location if the + // backing media is unreliable (e.g. raw NAND) etc. + // + // It is safe to assume the writing has been successful in this function. + return OkStatus(); + } // Do any work needed to finish the apply of the update and do a required // reboot of the device! |