243 lines
6.9 KiB
Plaintext
243 lines
6.9 KiB
Plaintext
|
|
= Citadel Resource Images
|
|
[topic]
|
|
@link[guide >index#internals]
|
|
|
|
Resource images are disk image files that are mounted read-only to create
|
|
the citadel filesystem. The first block (4096 bytes) of the image file
|
|
contains a header and immediately following the header is the raw disk
|
|
image contents.
|
|
|
|
The header contains information about the image including parameters for
|
|
configuring dm-verity to enforce the immutability of the image. The header
|
|
also contains a public key signature over the image information so that
|
|
the authenticity of the header information can be verified.
|
|
|
|
The root filesystem of citadel is also distributed as a resource image, and
|
|
this image will be installed to a disk partition for normal operation.
|
|
|
|
Resource images other than the root filesystem are mounted by creating loop
|
|
devices on the image file. Prior to mounting the image dm-verity is configured
|
|
on the loop device or the rootfs partition.
|
|
|
|
== Resource Image Types
|
|
|
|
Currently the following image types are defined for use in Citadel:
|
|
|
|
=== 1) Base Root Filesystem ("rootfs")
|
|
|
|
The base rootfs image is the only image type which is installed to a
|
|
partition. It is mounted as the root of the Citadel filesystem. When an
|
|
image is installed on a partition the 4906 byte header block is stored in
|
|
the last block (8 sectors) of the partition.
|
|
|
|
Citadel uses two partitions (A & B) for the root filesystem. This allows
|
|
updating one partition while the other one is being used. Then the system
|
|
can be rebooted into the updated rootfs partition. If the system fails to
|
|
boot after updating it will be reverted to use the working partition.
|
|
|
|
=== 2) Kernel Image ("kernel")
|
|
|
|
The kernel modules for the running kernel are stored in a resource image
|
|
so that the root filesystem is independent from the running kernel.
|
|
|
|
During boot, this image is mounted and the kernel modules and a bind mount
|
|
is created over /usr/lib/modules on the Citadel root filesystem.
|
|
|
|
=== 3) Extra Resource Image ("extra")
|
|
|
|
This image type contains additional directories of files which are mounted
|
|
during boot on the Citadel root filesystem. It contains files such as
|
|
firmware files and desktop icons which occupy substantial space but do not
|
|
need to be updated frequently.
|
|
|
|
By placing these files into a separate image the size of the root filesystem
|
|
image is reduced. This makes the more frequently updated rootfs image
|
|
smaller.
|
|
|
|
=== 4) Realm Filesystem Image ("realmfs")
|
|
|
|
This type of image contains the entire root filesystem for running a realm
|
|
container or VM. Unlike the other types of resource images, these images can
|
|
be modified and then signed with keys controlled by the user. This allows
|
|
updates and installation of software while still preserving the read-only
|
|
property.
|
|
|
|
=== Image Layout
|
|
|
|
Each resource image file reserves an initial 4096 byte block where a header is
|
|
stored. This is the maximum length of the header, which is generally much
|
|
smaller than this size.
|
|
|
|
Following the header is a raw disk filesystem image which may optionally be
|
|
compressed with xz compression algorithm. The disk image filesystem is ext4,
|
|
but this is an implementation detail which may change in the future. A header
|
|
flag (FLAG_DATA_COMPRESSED) indicates if an image is compressed and if so the
|
|
image must be decompressed before being used. Image updates are distributed in
|
|
compressed form and are decompressed once during installation.
|
|
|
|
When dm-verity is used a hash tree must be generated for the image. When an
|
|
image is installed it is first decompressed and then the dm-verity hash data
|
|
is generated. This hash data is stored in the image file immediately following
|
|
the image data and the flag FLAG_HASH_TREE is set to indicate this data is
|
|
present.
|
|
|
|
Image file:
|
|
[code]
|
|
[[[
|
|
[ Header ][ Ext4 Disk Image ][ dm-verity hash data ]
|
|
]]]
|
|
|
|
Partition:
|
|
|
|
[code]
|
|
[[[
|
|
[ Ext4 Disk Image ][ dm-verity hash data ][ unused space ][ Header ]
|
|
]]]
|
|
|
|
== Image Header
|
|
|
|
The image header contains the following fields.
|
|
|
|
[table]
|
|
[tr]
|
|
- Field
|
|
- Size
|
|
- Content
|
|
[tr]
|
|
* MAGIC
|
|
* 4 bytes
|
|
* ('S', 'G', 'O', 'S')
|
|
[tr]
|
|
* status
|
|
* 1 byte
|
|
* Used by images installed to partition
|
|
[tr]
|
|
* flags
|
|
* 1 byte
|
|
* Various flag values
|
|
[tr]
|
|
* metainfo-len
|
|
* 2 bytes
|
|
* 16 bit big-endian length
|
|
[tr]
|
|
* metainfo
|
|
* (metainfo-len) bytes
|
|
* TOML document containing key-value pairs
|
|
[tr]
|
|
* signature
|
|
* 64 bytes
|
|
* ed25519 signature over metainfo field
|
|
|
|
|
|
=== Header Fields
|
|
|
|
==== MAGIC
|
|
|
|
The initial 4 bytes are always set to the ascii bytes 'SGOS' so that a
|
|
valid image file can easily be identified.
|
|
|
|
==== status
|
|
|
|
The `status` field is used only on base rootfs image installed on a partition.
|
|
It must be set to 0 for all other images. The field is used to make decisions
|
|
about which parition to attempt to boot.
|
|
|
|
The status value is stored in the low nibble (4 bits) of this field and the
|
|
high nibble is reserved for counting boot attempts in `STATUS_TRY_BOOT` state.
|
|
|
|
The defined status values are:
|
|
|
|
[table]
|
|
[tr]
|
|
- status
|
|
- value
|
|
- description
|
|
[tr]
|
|
* STATUS_INVALID
|
|
* 0
|
|
* Partition does not contain a valid image
|
|
[tr]
|
|
* STATUS_NEW
|
|
* 1
|
|
* Newly written partition which has not yet been booted
|
|
[tr]
|
|
* STATUS_TRY_BOOT
|
|
* 2
|
|
* Set when booting a partition for the first time
|
|
[tr]
|
|
* STATUS_GOOD
|
|
* 3
|
|
* Partition has been successfully booted at least once
|
|
[tr]
|
|
* STATUS_FAILED
|
|
* 4
|
|
* Partition has failed to boot
|
|
[tr]
|
|
* STATUS_BAD_SIG
|
|
* 5
|
|
* Signature verification on metainfo failed
|
|
[tr]
|
|
* STATUS_BAD_META
|
|
* 6
|
|
* Parsing metainfo field failed
|
|
|
|
==== flags
|
|
|
|
[table]
|
|
[tr]
|
|
- flag
|
|
- value
|
|
- description
|
|
[tr]
|
|
* FLAG_PREFERRED_BOOT
|
|
* 0x01
|
|
* Override boot choice to boot from this partition
|
|
[tr]
|
|
* FLAG_HASH_TREE
|
|
* 0x02
|
|
* Image contains an appended dm-verity hash tree
|
|
[tr]
|
|
* FLAG_DATA_COMPRESSED
|
|
* 0x04
|
|
* Image is compressed with xz
|
|
|
|
==== metainfo-len
|
|
|
|
Length in bytes of the `metainfo` field.
|
|
|
|
Since header page has a fixed size of one block (4096 bytes), and all other
|
|
header fields have fixed sizes the maximum length of the `metainfo` field is
|
|
4096 - (4 + 2 + 2 + 64) = 4024 bytes
|
|
|
|
==== metainfo
|
|
|
|
==== signature
|
|
|
|
When the rootfs partition is chosen to mount, an attempt will be made to verify
|
|
the signature before configuring dm-verity. If this signature verification
|
|
fails, the partition status will be changed to `STATUS_BAD_SIG`
|
|
|
|
|
|
=== Booting
|
|
|
|
During boot of Citadel, the initramfs sets up the Citadel root filesystem. The
|
|
filesystem is built by locating and mounting three components:
|
|
|
|
* Base root filesystem
|
|
* Kernel modules
|
|
* Extra resources
|
|
|
|
The base root filesystem is stored on a partition unless running in certain
|
|
special modes such as installer and live disk. During installation the same
|
|
base root filesystem image is mounted from a loop mounted image file. This same
|
|
file will eventually be written to a partition during installation.
|
|
|
|
Kernel modules and extra resources are stored in file images which are
|
|
loop mounted during boot.
|
|
|
|
An additional type of resource image called a sealed application image exists
|
|
for the creation of immutable application image filesystems.
|
|
|
|
Resource images can optionally have dm-verity enabled when mounted.
|