Update Bundles
Updates are delivered to devices in the form of update bundles.
Rugix update bundles are based on a format specifically engineered for efficient and secure over-the-air updates. The format provides built-in support for cryptographic integrity checks, compression, and adaptive delta updates.
Introduction
An update bundle is a single file that may contain multiple update payloads. Typically, for each payload, the update bundle specifies a slot (see System Configuration: Slots and Boot Groups) to which the payload should be installed.
Before we continue, let's define a few terms:
- Slot Data: Data that will exist in a slot after a successful update.
- Payload File: Single file corresponding to a payload in an update bundle.
- Payload Data: Actual data of a payload stored in an update bundle.
For instance, if a slot corresponds to a block device, then the slot data and payload file may be a filesystem image. However, if a slot corresponds to a directory, then the slot data is the contents of this directory and the payload file may be a Tar archive of the directory's contents. Now, the payload data is derived from the payload file. For instance, the payload file may be compressed before being stored in an update bundle. While the payload file must be reconstructible from the update bundle alone, e.g., by decompressing the payload data stored in the bundle, the slot data may or may not be reconstructible from the bundle alone.
These considerations give rise to the following transformations:
The data that should end up in the slot after an update is first preprocessed to obtain a payload file, e.g., by creating a Tar archive from a directory. This payload file is then packed into an update bundle. When the update bundle is installed, the payload file is unpacked and then installed to the slot specified in the update bundle, e.g., by extracting the formerly created Tar archive.
Note that Rugix Ctrl implements streaming updates, i.e., the unpacking step will not reconstruct the entire payload file but instead stream it to the installation step in pieces as the update bundle is read, e.g., over the network.
Update Types
Update bundles can be built for two types of updates:
full
: For full system updates involving a boot flow.incremental
: For incremental updates not involving a boot flow.
For full system updates, a boot group must be provided to rugix-ctrl
as a installation target (if there are more than two boot groups).
For incremental system updates, a boot group can be provided but it does not have to be.
Bundle Creation
To work with bundles, you can use Rugix Bundler (rugix-bundler
).
You can download pre-built binaries from the Releases page of Rugix's Git repository.
If you are using Rugix Bakery, you can also use ./run-bakery bundler
.
Rugix Bundler offers a subcommand for creating a bundle from a bundle directory:
rugix-bundler bundle <bundle directory> <bundle path.rugixb>
A bundle directory is a directory with the following structure:
rugix-bundle.toml
: Rugix bundle manifest.payloads/
: Directory containing the payload files.
Rugix Bakery will generate bundles with good default settings so you do not have to care about the details.
Here is an example of a bundle manifest:
#:schema https://raw.githubusercontent.com/silitics/rugix/refs/tags/v0.8.0/schemas/rugix-bundle-manifest.schema.json
update-type = "full"
hash-algorithm = "sha512-256"
[[payloads]]
filename = "boot.vfat"
[payloads.delivery]
type = "slot"
slot = "boot"
[payloads.block-encoding]
hash-algorithm = "sha512-256"
chunker = "casync-64"
compression = { type = "xz", level = 9 }
deduplication = true
[[payloads]]
filename = "system.ext4"
[payloads.delivery]
type = "slot"
slot = "system"
[payloads.block-encoding]
hash-algorithm = "sha512-256"
chunker = "casync-64"
compression = { type = "xz", level = 9 }
deduplication = true
The bundle contains two payloads, a filesystem for a boot partition (boot
slot) and a filesystem for a system partition (system
slot).
The hash-algorithm
property specifies a hash algorithm for ensuring a bundle's integrity.
By default, an update bundle will include hashes of the payloads as well as other integral parts of the bundle using the specified algorithm.
When installing an update bundle, you can use --verify-bundle <hash>
where <hash>
is a hash of the bundle's header that can be obtained with:
rugix-bundler hash <bundle path.rugixb>
Note that this is not a hash over the entire bundle but just the bundle's header. The header of the bundle, in turn, contains hashes of the payload headers as well as of the payloads themselves. Combined these hashes form a Merkle tree. That way, by providing the hash of the root, Rugix Ctrl can verify different parts of the bundle individually as they are read.
Payload Delivery
A payload can have two types of delivery mechanisms:
type = "slot"
: Payload is installed to a slot.type = "execute"
: Payload is delivered by executing a command receiving the payload file via stdin.
For instance, to run a bash script you can use the following configuration:
[[payloads]]
filename = "update-script.sh"
[payloads.delivery]
type = "execute"
handler = ["/bin/bash", "-"]
[payloads.block-encoding]
hash-algorithm = "sha512-256"
chunker = "fixed-64"
Always add a block index/block encoding, otherwise untrusted data may be fed into the command.1
The execute
delivery mechanism is extremely flexible and can be used to deliver all kinds of updates to a device.