mirror of
https://github.com/systemd/systemd
synced 2026-03-28 17:54:51 +01:00
Compare commits
13 Commits
1641c2b112
...
5b81fa7ae1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b81fa7ae1 | ||
|
|
ca3f47eff3 | ||
|
|
ddd19fce8a | ||
|
|
2bdc8dc341 | ||
|
|
636c8a1f55 | ||
|
|
2c424ee0aa | ||
|
|
54dcf847b1 | ||
|
|
77617993ee | ||
|
|
c2fa92e7e8 | ||
|
|
d5fcc5b053 | ||
|
|
88b3300fdc | ||
|
|
8ee9615e10 | ||
|
|
1420cfb4b4 |
15
TODO
15
TODO
@ -83,6 +83,19 @@ Janitorial Clean-ups:
|
||||
|
||||
Features:
|
||||
|
||||
* add high-level lockdown level for GPT dissection logic: e.g. an enum that can
|
||||
be ANY (to mount anything), TRUSTED (to require that /usr is on signed
|
||||
verity, but rest doesn't matter), LOCKEDDOWN (to require that everything is
|
||||
on signed verity, except for ESP), SUPERLOCKDOWN (like LOCKEDDOWN but ESP not
|
||||
allowed). And then maybe some flavours of that that declare what is expected
|
||||
from home/srv/var… Then, add a new cmdline flag to all tools that parse such
|
||||
images, to configure this. Also, add a kernel cmdline option for this, to be
|
||||
honoured by the gpt auto generator.
|
||||
|
||||
* nspawn: maybe optionally insert .nspawn file as GPT partition into images, so
|
||||
that such container images are entirely stand-alone and can be updated as
|
||||
one.
|
||||
|
||||
* we probably should extend the root verity hash of the root fs into some PCR
|
||||
on boot. (i.e. maybe add a crypttab option tpm2-measure=8 or so to measure it
|
||||
into PCR 8)
|
||||
@ -102,8 +115,6 @@ Features:
|
||||
* tpm2: figure out if we need to do anything for TPM2 parameter encryption? And
|
||||
if so, what precisely?
|
||||
|
||||
* insert pkcs7 signature for verity gpt
|
||||
|
||||
* when mounting disk images: if IMAGE_ID/IMAGE_VERSION is set in os-release
|
||||
data in the image, make sure the image filename actually matches this, so
|
||||
that images cannot be misused.
|
||||
|
||||
@ -4,7 +4,7 @@ category: Concepts
|
||||
layout: default
|
||||
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
---
|
||||
# The Discoverable Partitions Specification
|
||||
# The Discoverable Partitions Specification (DPS)
|
||||
|
||||
_TL;DR: Let's automatically discover, mount and enable the root partition,
|
||||
`/home/`, `/srv/`, `/var/` and `/var/tmp/` and the swap partitions based on
|
||||
@ -50,7 +50,7 @@ Interface](https://systemd.io/BOOT_LOADER_INTERFACE).
|
||||
| `77055800-792c-4f94-b39a-98c91b762bb6` | _Root Partition (LoongArch 64-bit)_ | ditto | ditto |
|
||||
| `60d5a7fe-8e7d-435c-b714-3dd8162144e1` | _Root Partition (RISC-V 32-bit)_ | ditto | ditto |
|
||||
| `72ec70a6-cf74-40e6-bd49-4bda08e8f224` | _Root Partition (RISC-V 64-bit)_ | ditto | ditto |
|
||||
| `d13c5d3b-b5d1-422a-b29f-9454fdc89d76` | _Root Verity Partition (x86)_ | A dm-verity superblock followed by hash data | Contains dm-verity integrity hash data for the matching root partition. If this feature is used the partition UUID of the root partition should be the first 128 bits of the root hash of the dm-verity hash data, and the partition UUID of this dm-verity partition should be the final 128 bits of it, so that the root partition and its verity partition can be discovered easily, simply by specifying the root hash. |
|
||||
| `d13c5d3b-b5d1-422a-b29f-9454fdc89d76` | _Root Verity Partition (x86)_ | A dm-verity superblock followed by hash data | Contains dm-verity integrity hash data for the matching root partition. If this feature is used the partition UUID of the root partition should be the first 128 bits of the root hash of the dm-verity hash data, and the partition UUID of this dm-verity partition should be the final 128 bits of it, so that the root partition and its Verity partition can be discovered easily, simply by specifying the root hash. |
|
||||
| `2c7357ed-ebd2-46d9-aec1-23d437ec2bf5` | _Root Verity Partition (x86-64)_ | ditto | ditto |
|
||||
| `7386cdf2-203c-47a9-a498-f2ecce45a2d6` | _Root Verity Partition (32-bit ARM)_ | ditto | ditto |
|
||||
| `df3300ce-d69f-4c92-978c-9bfb0f38d820` | _Root Verity Partition (64-bit ARM/AArch64)_ | ditto | ditto |
|
||||
@ -58,6 +58,14 @@ Interface](https://systemd.io/BOOT_LOADER_INTERFACE).
|
||||
| `f3393b22-e9af-4613-a948-9d3bfbd0c535` | _Root Verity Partition (LoongArch 64-bit)_ | ditto | ditto |
|
||||
| `ae0253be-1167-4007-ac68-43926c14c5de` | _Root Verity Partition (RISC-V 32-bit)_ | ditto | ditto |
|
||||
| `b6ed5582-440b-4209-b8da-5ff7c419ea3d` | _Root Verity Partition (RISC-V 64-bit)_ | ditto | ditto |
|
||||
| `5996fc05-109c-48de-808b-23fa0830b676` | _Root Verity Signature Partition (x86)_ | A serialized JSON object, see below | Contains a root hash and a PKCS#7 signature for it, permitting signed dm-verity GPT images |
|
||||
| `41092b05-9fc8-4523-994f-2def0408b176` | _Root Verity Signature Partition (x86-64)_ | ditto | ditto |
|
||||
| `42b0455f-eb11-491d-98d3-56145ba9d037` | _Root Verity Signature Partition (32-bit ARM)_ | ditto | ditto |
|
||||
| `6db69de6-29f4-4758-a7a5-962190f00ce3` | _Root Verity Signature Partition (64-bit ARM/AArch64)_ | ditto | ditto |
|
||||
| `e98b36ee-32ba-4882-9b12-0ce14655f46a` | _Root Verity Signature Partition (Itanium/IA-64)_ | ditto | ditto |
|
||||
| `5afb67eb-ecc8-4f85-ae8e-ac1e7c50e7d0` | _Root Verity Signature Partition (LoongArch 64-bit)_ | ditto | ditto |
|
||||
| `3a112a75-8729-4380-b4cf-764d79934448` | _Root Verity Signature Partition (RISC-V 32-bit)_ | ditto | ditto |
|
||||
| `efe0f087-ea8d-4469-821a-4c2a96a8386a` | _Root Verity Signature Partition (RISC-V 64-bit)_ | ditto | ditto |
|
||||
| `75250d76-8cc6-458e-bd66-bd47cc81a812` | _`/usr/` Partition (x86)_ | Any native, optionally in LUKS | Similar semantics to root partition, but just the `/usr/` partition. |
|
||||
| `8484680c-9521-48c6-9c11-b0720656f69e` | _`/usr/` Partition (x86-64)_ | ditto | ditto |
|
||||
| `7d0359a3-02b3-4f0a-865c-654403e70625` | _`/usr/` Partition (32-bit ARM)_ | ditto | ditto |
|
||||
@ -74,6 +82,14 @@ Interface](https://systemd.io/BOOT_LOADER_INTERFACE).
|
||||
| `f46b2c26-59ae-48f0-9106-c50ed47f673d` | _`/usr/` Verity Partition (LoongArch 64-bit)_ | ditto | ditto |
|
||||
| `cb1ee4e3-8cd0-4136-a0a4-aa61a32e8730` | _`/usr/` Verity Partition (RISC-V 32-bit)_ | ditto | ditto |
|
||||
| `8f1056be-9b05-47c4-81d6-be53128e5b54` | _`/usr/` Verity Partition (RISC-V 64-bit)_ | ditto | ditto |
|
||||
| `974a71c0-de41-43c3-be5d-5c5ccd1ad2c0` | _`/usr/` Verity Signature Partition (x86)_ | A serialized JSON object, see below | Similar semantics to root Verity signature partition, but just for the `/usr/` partition. |
|
||||
| `e7bb33fb-06cf-4e81-8273-e543b413e2e2` | _`/usr/` Verity Signature Partition (x86-64)_ | ditto | ditto |
|
||||
| `d7ff812f-37d1-4902-a810-d76ba57b975a` | _`/usr/` Verity Signature Partition (32-bit ARM)_ | ditto | ditto |
|
||||
| `c23ce4ff-44bd-4b00-b2d4-b41b3419e02a` | _`/usr/` Verity Signature Partition (64-bit ARM/AArch64)_ | ditto | ditto |
|
||||
| `8de58bc2-2a43-460d-b14e-a76e4a17b47f` | _`/usr/` Verity Signature Partition (Itanium/IA-64)_ | ditto | ditto |
|
||||
| `b024f315-d330-444c-8461-44bbde524e99` | _`/usr/` Verity Signature Partition (LoongArch 64-bit)_ | ditto | ditto |
|
||||
| `c3836a13-3137-45ba-b583-b16c50fe5eb4` | _`/usr/` Verity Signature Partition (RISC-V 32-bit)_ | ditto | ditto |
|
||||
| `d2f9000a-7a18-453f-b5cd-4d32f77a7b32` | _`/usr/` Verity Signature Partition (RISC-V 64-bit)_ | ditto | ditto |
|
||||
| `933ac7e1-2eb4-4f13-b844-0e14e2aef915` | _Home Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/home/`. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/home`. |
|
||||
| `3b8f8425-20e0-4f3b-907f-1a25a76f98e8` | _Server Data Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/srv/`. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/srv`. |
|
||||
| `4d21b016-b534-45c2-a9fb-5c16e091fd2d` | _Variable Data Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/var/` — under the condition that its partition UUID matches the first 128 bits of `HMAC-SHA256(machine-id, 0x4d21b016b53445c2a9fb5c16e091fd2d)` (i.e. the SHA256 HMAC hash of the binary type UUID keyed by the machine ID as read from [`/etc/machine-id`](https://www.freedesktop.org/software/systemd/man/machine-id.html). This special requirement is made because `/var/` (unlike the other partition types listed here) is inherently private to a specific installation and cannot possibly be shared between multiple OS installations on the same disk, and thus should be bound to a specific instance of the OS, identified by its machine ID. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/var`. |
|
||||
@ -87,8 +103,8 @@ Other GPT type IDs might be used on Linux, for example to mark software RAID or
|
||||
LVM partitions. The definitions of those GPT types is outside of the scope of
|
||||
this specification.
|
||||
|
||||
[systemd-id128(1)](http://www.freedesktop.org/software/systemd/man/systemd-id128.html)
|
||||
may be used to list those UUIDs.
|
||||
[systemd-id128(1)](http://www.freedesktop.org/software/systemd/man/systemd-id128.html)'s
|
||||
`show` command may be used to list those GPT partition type UUIDs.
|
||||
|
||||
## Partition Names
|
||||
|
||||
@ -97,31 +113,36 @@ human-friendly, descriptive partition names in the GPT partition table, for
|
||||
example "*Home*", "*Server* *Data*", "*Fedora* *Root*" and similar, possibly
|
||||
localized.
|
||||
|
||||
For the Root/Verity/Verity signature partitions it might make sense to use a
|
||||
versioned naming scheme reflecting the OS name and its version,
|
||||
e.g. "fooOS_2021.4" or similar.
|
||||
|
||||
## Partition Flags
|
||||
|
||||
This specification defines three GPT partition flags that may be set for the
|
||||
partition types defined above:
|
||||
|
||||
1. For the root, `/usr/`, Verity, home, server data, variable data, temporary data,
|
||||
swap and extended boot loader partitions, the partition flag bit 63
|
||||
("*no-auto*") may be used to turn off auto-discovery for the specific
|
||||
partition. If set, the partition will not be automatically mounted or
|
||||
enabled.
|
||||
1. For the root, `/usr/`, Verity, Verity signature, home, server data, variable
|
||||
data, temporary data, swap and extended boot loader partitions, the
|
||||
partition flag bit 63 ("*no-auto*") may be used to turn off auto-discovery
|
||||
for the specific partition. If set, the partition will not be automatically
|
||||
mounted or enabled.
|
||||
|
||||
2. For the root, `/usr/`, Verity, home, server data, variable data, temporary
|
||||
data and extended boot loader partitions, the partition flag bit 60
|
||||
("*read-only*") may be used to mark a partition for read-only mounts only.
|
||||
If set, the partition will be mounted read-only instead of read-write. Note
|
||||
that the variable data partition and the temporary data partition will
|
||||
generally not be able to serve their purpose if marked read-only, since by
|
||||
their very definition they are supposed to be mutable. (The home and server
|
||||
data partitions are generally assumed to be mutable as well, but the
|
||||
requirement for them is not equally strong.) Because of that, while the
|
||||
read-only flag is defined and supported, it's almost never a good idea to
|
||||
actually use it for these partitions. Also note that Verity partitions are
|
||||
by their semantics always read-only. The flag is hence of little effect for
|
||||
them, and it is recommended to set it unconditionally for the Verity
|
||||
partition types.
|
||||
2. For the root, `/usr/`, Verity, Verity signature home, server data, variable
|
||||
data, temporary data and extended boot loader partitions, the partition flag
|
||||
bit 60 ("*read-only*") may be used to mark a partition for read-only mounts
|
||||
only. If set, the partition will be mounted read-only instead of
|
||||
read-write. Note that the variable data partition and the temporary data
|
||||
partition will generally not be able to serve their purpose if marked
|
||||
read-only, since by their very definition they are supposed to be
|
||||
mutable. (The home and server data partitions are generally assumed to be
|
||||
mutable as well, but the requirement for them is not equally strong.)
|
||||
Because of that, while the read-only flag is defined and supported, it's
|
||||
almost never a good idea to actually use it for these partitions. Also note
|
||||
that Verity and signature partitions are by their semantics always
|
||||
read-only. The flag is hence of little effect for them, and it is
|
||||
recommended to set it unconditionally for the Verity and signature partition
|
||||
types.
|
||||
|
||||
3. For the root, `/usr/`, home, server data, variable data, temporary data and
|
||||
extended boot loader partitions, the partition flag bit 59
|
||||
@ -129,11 +150,11 @@ partition types defined above:
|
||||
of the contained file system to the size of the partition when
|
||||
mounted. Tools that automatically mount disk image with a GPT partition
|
||||
table are suggested to implicitly grow the contained file system to the
|
||||
partition size they are contained in. This flag is without effect on
|
||||
partitions marked read-only.
|
||||
partition size they are contained in, if they are found to be smaller. This
|
||||
flag is without effect on partitions marked read-only.
|
||||
|
||||
Note that the first two flag definitions happen to map nicely to the ones used
|
||||
by Microsoft Basic Data Partitions.
|
||||
Note that the first two flag definitions happen to correspond nicely to the
|
||||
same ones used by Microsoft Basic Data Partitions.
|
||||
|
||||
All three of these flags generally affect only auto-discovery and automatic
|
||||
mounting of disk images. If partitions marked with these flags are mounted
|
||||
@ -142,6 +163,63 @@ using low-level commands like
|
||||
[mount(2)](https://man7.org/linux/man-pages/man2/mount.2.html), they typically
|
||||
have no effect.
|
||||
|
||||
## Verity
|
||||
|
||||
The Root/`/usr/` partition types and their matching Verity and Verity signature
|
||||
partitions enable relatively automatic handling of `dm-verity` protected
|
||||
setups. These types are defined with two modes of operation in mind:
|
||||
|
||||
1. A trusted Verity root hash is passed in externally, for example is specified
|
||||
on the kernel command line that is signed along with the kernel image using
|
||||
SecureBoot PE signing (which in turn is tested against a set of
|
||||
firmware-provided set of signing keys). If so, discovery and setup of a
|
||||
Verity volume may be fully automatic: if the root partition's UUID is chosen
|
||||
to match the first 128 bit of the root hash, and the matching Verity
|
||||
partition UUIDs is chosen to match the last 128bit of the root hash, then
|
||||
automatic discovery and match-up of the two partitions is possible, as the
|
||||
root hash is enough to both find the partitions and then combine them in a
|
||||
Verity volume. In this mode a Verity signature partition is not used and
|
||||
unnecessary.
|
||||
|
||||
2. A Verity signature partition is included on the disk, with a signature to be
|
||||
tested against a system-provided set of signing keys. The signature
|
||||
partition primarily contains two fields: the root hash to use, and a PKCS#7
|
||||
signature of it, using a signature key trusted by the OS. If so, discovery
|
||||
and setup of a Verity volume may be fully automatic. First, the specified
|
||||
root hash is validated with the signature and the OS-provided trusted
|
||||
keys. If the signature checks out the root hash is then used in the same way
|
||||
as in the first mode of operation described above.
|
||||
|
||||
Both modes of operation may be combined in a single image. This is particularly
|
||||
useful for images that shall be usable in two different contexts: for example
|
||||
an image that shall be able to boot directly on UEFI systems (in which
|
||||
case it makes sense to include the root hash on the kernel command line that is
|
||||
included in the signed kernel image to boot, as per mode of operation #1
|
||||
above), but also be able to used as image for a container engine (such as
|
||||
`systemd-nspawn`), which can use the signature partition to validate the image,
|
||||
without making use of the signed kernel image (and thus following mode of
|
||||
operation #2).
|
||||
|
||||
The Verity signature partition's contents should be a serialized JSON object in
|
||||
text form, padded with NUL bytes to the next multiple of 4096 bytes in
|
||||
size. Currently three fields are defined for the JSON object:
|
||||
|
||||
1. The (mandatory) `rootHash` field should be a string containing the Verity root hash,
|
||||
formatted as series of (lowercase) hex characters.
|
||||
|
||||
2. The (mandatory) `signature` field should be a string containing the PKCS#7
|
||||
signature of the root hash, in Base64-encoded DER format. This should be the
|
||||
same format used by the Linux kernel's dm-verity signature logic, i.e. the
|
||||
signed data should be the exact string representation of the hash, as stored
|
||||
in `rootHash` above.
|
||||
|
||||
3. The (optional) `certificateFingerprint` field should be a string containing
|
||||
a SHA256 fingerprint of the X.509 certificate for the key that signed the
|
||||
root hash, formatted as series of (lowercase) hex characters (no `:`
|
||||
separators or such).
|
||||
|
||||
More fields might be added in later revisions of this specification.
|
||||
|
||||
## Suggested Mode of Operation
|
||||
|
||||
An *installer* that repartitions the hard disk _should_ use the above UUID
|
||||
@ -158,20 +236,20 @@ An *installer* _may_ omit creating entries in `/etc/fstab` for root, `/home/`,
|
||||
`/srv/`, `/var/`, `/var/tmp` and for the swap partitions if they use these UUID
|
||||
partition types, and are the first partitions on the disk of each type. If the
|
||||
ESP shall be mounted to `/efi/` (or `/boot/`), it may additionally omit
|
||||
creating the entry for it in `/etc/fstab`. If an extended boot partition is
|
||||
used, or if the EFI partition shall not be mounted to `/efi/` or `/boot/`, it
|
||||
_must_ create `/etc/fstab` entries for them. If other partitions are used (for
|
||||
example for `/usr/` or `/var/lib/mysql/`), the installer _must_ register these
|
||||
in `/etc/fstab`. The `root=` parameter passed to the kernel by the boot loader
|
||||
may be omitted if the root partition is the first one on the disk of its type.
|
||||
If the root partition is not the first one on the disk, the `root=` parameter
|
||||
_must_ be passed to the kernel by the boot loader. An installer that mounts a
|
||||
root, `/usr/`, `/home/`, `/srv/`, `/var/`, or `/var/tmp/` file system with the
|
||||
partition types defined as above which contains a LUKS header _must_ call the
|
||||
device mapper device "root", "usr", "home", "srv", "var" or "tmp",
|
||||
respectively. This is necessary to ensure that the automatic discovery will
|
||||
never result in different device mapper names than any static configuration by
|
||||
the installer, thus eliminating possible naming conflicts and ambiguities.
|
||||
creating the entry for it in `/etc/fstab`. If the EFI partition shall not be
|
||||
mounted to `/efi/` or `/boot/`, it _must_ create `/etc/fstab` entries for them.
|
||||
If other partitions are used (for example for `/usr/local/` or
|
||||
`/var/lib/mysql/`), the installer _must_ register these in `/etc/fstab`. The
|
||||
`root=` parameter passed to the kernel by the boot loader may be omitted if the
|
||||
root partition is the first one on the disk of its type. If the root partition
|
||||
is not the first one on the disk, the `root=` parameter _must_ be passed to the
|
||||
kernel by the boot loader. An installer that mounts a root, `/usr/`, `/home/`,
|
||||
`/srv/`, `/var/`, or `/var/tmp/` file system with the partition types defined
|
||||
as above which contains a LUKS header _must_ call the device mapper device
|
||||
"root", "usr", "home", "srv", "var" or "tmp", respectively. This is necessary
|
||||
to ensure that the automatic discovery will never result in different device
|
||||
mapper names than any static configuration by the installer, thus eliminating
|
||||
possible naming conflicts and ambiguities.
|
||||
|
||||
An *operating* *system* _should_ automatically discover and mount the first
|
||||
root partition that does not have the no-auto flag set (as described above) by
|
||||
|
||||
@ -23,17 +23,17 @@ All tools:
|
||||
* `$SYSTEMD_OFFLINE=[0|1]` — if set to `1`, then `systemctl` will refrain from
|
||||
talking to PID 1; this has the same effect as the historical detection of
|
||||
`chroot()`. Setting this variable to `0` instead has a similar effect as
|
||||
`SYSTEMD_IGNORE_CHROOT=1`; i.e. tools will try to communicate with PID 1 even
|
||||
if a `chroot()` environment is detected. You almost certainly want to set
|
||||
this to `1` if you maintain a package build system or similar and are trying
|
||||
to use a modern container system and not plain `chroot()`.
|
||||
`$SYSTEMD_IGNORE_CHROOT=1`; i.e. tools will try to communicate with PID 1
|
||||
even if a `chroot()` environment is detected. You almost certainly want to
|
||||
set this to `1` if you maintain a package build system or similar and are
|
||||
trying to use a modern container system and not plain `chroot()`.
|
||||
|
||||
* `$SYSTEMD_IGNORE_CHROOT=1` — if set, don't check whether being invoked in a
|
||||
`chroot()` environment. This is particularly relevant for systemctl, as it
|
||||
will not alter its behaviour for `chroot()` environments if set. Normally it
|
||||
refrains from talking to PID 1 in such a case; turning most operations such
|
||||
as `start` into no-ops. If that's what's explicitly desired, you might
|
||||
consider setting `SYSTEMD_OFFLINE=1`.
|
||||
consider setting `$SYSTEMD_OFFLINE=1`.
|
||||
|
||||
* `$SD_EVENT_PROFILE_DELAYS=1` — if set, the sd-event event loop implementation
|
||||
will print latency information at runtime.
|
||||
@ -96,7 +96,7 @@ All tools:
|
||||
* `$SYSTEMD_RDRAND=0` — if set, the RDRAND instruction will never be used,
|
||||
even if the CPU supports it.
|
||||
|
||||
* `$SYSTEMD_SECCOMP=0` – if set, seccomp filters will not be enforced, even if
|
||||
* `$SYSTEMD_SECCOMP=0` — if set, seccomp filters will not be enforced, even if
|
||||
support for it is compiled in and available in the kernel.
|
||||
|
||||
* `$SYSTEMD_LOG_SECCOMP=1` — if set, system calls blocked by seccomp filtering,
|
||||
@ -189,7 +189,7 @@ All tools:
|
||||
|
||||
`systemd-udevd`:
|
||||
|
||||
* `$NET_NAMING_SCHEME=` – if set, takes a network naming scheme (i.e. one of
|
||||
* `$NET_NAMING_SCHEME=` — if set, takes a network naming scheme (i.e. one of
|
||||
"v238", "v239", "v240"…, or the special value "latest") as parameter. If
|
||||
specified udev's `net_id` builtin will follow the specified naming scheme
|
||||
when determining stable network interface names. This may be used to revert
|
||||
@ -267,13 +267,13 @@ All tools:
|
||||
|
||||
`systemd-firstboot` and `localectl`:
|
||||
|
||||
* `SYSTEMD_LIST_NON_UTF8_LOCALES=1` – if set, non-UTF-8 locales are listed among
|
||||
* `$SYSTEMD_LIST_NON_UTF8_LOCALES=1` — if set, non-UTF-8 locales are listed among
|
||||
the installed ones. By default non-UTF-8 locales are suppressed from the
|
||||
selection, since we are living in the 21st century.
|
||||
|
||||
`systemd-sysext`:
|
||||
|
||||
* `SYSTEMD_SYSEXT_HIERARCHIES` – this variable may be used to override which
|
||||
* `$SYSTEMD_SYSEXT_HIERARCHIES` — this variable may be used to override which
|
||||
hierarchies are managed by `systemd-sysext`. By default only `/usr/` and
|
||||
`/opt/` are managed, and directories may be added or removed to that list by
|
||||
setting this environment variable to a colon-separated list of absolute
|
||||
@ -284,7 +284,7 @@ All tools:
|
||||
|
||||
`systemd-tmpfiles`:
|
||||
|
||||
* `SYSTEMD_TMPFILES_FORCE_SUBVOL` — if unset, `v`/`q`/`Q` lines will create
|
||||
* `$SYSTEMD_TMPFILES_FORCE_SUBVOL` — if unset, `v`/`q`/`Q` lines will create
|
||||
subvolumes only if the OS itself is installed into a subvolume. If set to `1`
|
||||
(or another value interpreted as true), these lines will always create
|
||||
subvolumes if the backing filesystem supports them. If set to `0`, these
|
||||
@ -318,21 +318,49 @@ fuzzers:
|
||||
Note that is may be also useful to set `$SYSTEMD_LOG_LEVEL`, since all logging
|
||||
is suppressed by default.
|
||||
|
||||
systemd-importd:
|
||||
`systemd-importd`:
|
||||
|
||||
* `SYSTEMD_IMPORT_BTRFS_SUBVOL` – takes a boolean, which controls whether to
|
||||
* `$SYSTEMD_IMPORT_BTRFS_SUBVOL` — takes a boolean, which controls whether to
|
||||
prefer creating btrfs subvolumes over plain directories for machine
|
||||
images. Has no effect on non-btrfs file systems where subvolumes are not
|
||||
available anyway. If not set, defaults to true.
|
||||
|
||||
* `SYSTEMD_IMPORT_BTRFS_QUOTA` – takes a boolean, which controls whether to set
|
||||
* `$SYSTEMD_IMPORT_BTRFS_QUOTA` — takes a boolean, which controls whether to set
|
||||
up quota automatically for created btrfs subvolumes for machine images. If
|
||||
not set, defaults to true. Has no effect if machines are placed in regular
|
||||
directories, because btrfs subvolumes are not supported or disabled. If
|
||||
enabled, the quota group of the subvolume is automatically added to a
|
||||
combined quota group for all such machine subvolumes.
|
||||
|
||||
* `SYSTEMD_IMPORT_SYNC` – takes a boolean, which controls whether to
|
||||
* `$SYSTEMD_IMPORT_SYNC` — takes a boolean, which controls whether to
|
||||
synchronize images to disk after installing them, before completing the
|
||||
operation. If not set, defaults to true. If disabled installation of images
|
||||
will be quicker, but not as safe.
|
||||
|
||||
`systemd-dissect`, `systemd-nspawn` and all other tools that may operate on
|
||||
disk images with `--image=` or similar:
|
||||
|
||||
* `$SYSTEMD_DISSECT_VERITY_SIDECAR` — takes a boolean, which controls whether to
|
||||
load "sidecar" Verity metadata files. If enabled (which is the default),
|
||||
whenever a disk image is used, a set of files with the `.roothash`,
|
||||
`.usrhash`, `.roothash.p7s`, `.usrhash.p7s`, `.verity` suffixes are searched
|
||||
adjacent to disk image file, containing the Verity root hashes, their
|
||||
signatures or the Verity data itself. If disabled this automatic discovery of
|
||||
Verity metadata files is turned off.
|
||||
|
||||
* `$SYSTEMD_DISSECT_VERITY_EMBEDDED` — takes a boolean, which controls whether
|
||||
to load the embedded Verity signature data. If enabled (which is the
|
||||
default), Verity root hash information and a suitable signature is
|
||||
automatically acquired from a signature partition, following the
|
||||
[Discoverable Partitions
|
||||
Specification](https://systemd.io/DISCOVERABLE_PARTITIONS). If disabled any
|
||||
such partition is ignored. Note that this only disables discovery of the root
|
||||
hash and its signature, the Verity data partition itself is still searched in
|
||||
the GPT image.
|
||||
|
||||
* `$SYSTEMD_DISSECT_VERITY_SIGNATURE` — takes a boolean, which controls whether
|
||||
to validate the signature of the Verity root hash if available. If enabled
|
||||
(which is the default), the signature of suitable disk images is validated
|
||||
against any of the certificates in `/etc/verity.d/*.crt` (and similar
|
||||
directores in `/usr/lib/`, `/run`, …) or passed to the kernel for validation
|
||||
against its built-in certificates.
|
||||
|
||||
@ -198,7 +198,11 @@ sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:*:svnDefaul
|
||||
sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvrP02A_C106.60E:*:svnDefaultstring:pnDefaultstring:*
|
||||
ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
|
||||
|
||||
# Chuwi Hi10 Pro
|
||||
# Chuwi Hi10 Plus (CWI527)
|
||||
sensor:modalias:acpi:BOSC0200*:dmi:*:svnCHUWIINNOVATIONANDTECHNOLOGY*:pnHi10plustablet:*
|
||||
ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
|
||||
|
||||
# Chuwi Hi10 Pro (CWI529)
|
||||
sensor:modalias:acpi:BOSC0200*:dmi:*:svn*CHUWIINNOVATIONANDTECHNOLOGY*:pnHi10protablet:*
|
||||
ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
|
||||
|
||||
@ -281,6 +285,14 @@ sensor:modalias:acpi:KIOX000A*:dmi:*:svncube:pni8-T:*
|
||||
sensor:modalias:acpi:KIOX000A*:dmi:*:svnALLDOCUBE:pni1102:*
|
||||
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
|
||||
|
||||
#########################################
|
||||
# Cyberbook
|
||||
#########################################
|
||||
|
||||
# Cyberbook T116
|
||||
sensor:modalias:acpi:KIOX000A*:dmi:*:rvnDefaultstring:rnCherryTrailCR:*:sku20170531:*
|
||||
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
|
||||
|
||||
#########################################
|
||||
# Cytrix (Mytrix)
|
||||
#########################################
|
||||
|
||||
@ -1913,6 +1913,13 @@ int setup_namespace(
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to dissect image: %m");
|
||||
|
||||
r = dissected_image_load_verity_sig_partition(
|
||||
dissected_image,
|
||||
loop_device->fd,
|
||||
&verity);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_decrypt(
|
||||
dissected_image,
|
||||
NULL,
|
||||
|
||||
@ -515,7 +515,9 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) {
|
||||
if (arg_verity_settings.data_path)
|
||||
r = table_add_cell(t, NULL, TABLE_STRING, "external");
|
||||
else if (dissected_image_verity_candidate(m, i))
|
||||
r = table_add_cell(t, NULL, TABLE_STRING, yes_no(dissected_image_verity_ready(m, i)));
|
||||
r = table_add_cell(t, NULL, TABLE_STRING,
|
||||
dissected_image_verity_sig_ready(m, i) ? "signed" :
|
||||
yes_no(dissected_image_verity_ready(m, i)));
|
||||
else
|
||||
r = table_add_cell(t, NULL, TABLE_EMPTY, NULL);
|
||||
if (r < 0)
|
||||
@ -803,6 +805,13 @@ static int run(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_load_verity_sig_partition(
|
||||
m,
|
||||
d->fd,
|
||||
&arg_verity_settings);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
switch (arg_action) {
|
||||
|
||||
case ACTION_DISSECT:
|
||||
|
||||
@ -5710,8 +5710,16 @@ static int run(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
if (!arg_verity_settings.root_hash && dissected_image->has_verity)
|
||||
log_notice("Note: image %s contains verity information, but no root hash specified! Proceeding without integrity checking.", arg_image);
|
||||
r = dissected_image_load_verity_sig_partition(
|
||||
dissected_image,
|
||||
loop->fd,
|
||||
&arg_verity_settings);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
if (dissected_image->has_verity && !arg_verity_settings.root_hash && !dissected_image->has_verity_sig)
|
||||
log_notice("Note: image %s contains verity information, but no root hash specified and no embedded "
|
||||
"root hash signature found! Proceeding without integrity checking.", arg_image);
|
||||
|
||||
r = dissected_image_decrypt_interactively(
|
||||
dissected_image,
|
||||
|
||||
@ -9,13 +9,11 @@
|
||||
#include <openssl/x509v3.h>
|
||||
|
||||
#include "io-util.h"
|
||||
#include "openssl-util.h"
|
||||
#include "resolved-dns-stream.h"
|
||||
#include "resolved-dnstls.h"
|
||||
#include "resolved-manager.h"
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(SSL*, SSL_free, NULL);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(BIO*, BIO_free, NULL);
|
||||
|
||||
static int dnstls_flush_write_buffer(DnsStream *stream) {
|
||||
ssize_t ss;
|
||||
|
||||
|
||||
@ -11,6 +11,12 @@
|
||||
#include <sys/wait.h>
|
||||
#include <sysexits.h>
|
||||
|
||||
#if HAVE_OPENSSL
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/x509.h>
|
||||
#endif
|
||||
|
||||
#include "sd-device.h"
|
||||
#include "sd-id128.h"
|
||||
|
||||
@ -18,6 +24,7 @@
|
||||
#include "ask-password-api.h"
|
||||
#include "blkid-util.h"
|
||||
#include "blockdev-util.h"
|
||||
#include "conf-files.h"
|
||||
#include "copy.h"
|
||||
#include "cryptsetup-util.h"
|
||||
#include "def.h"
|
||||
@ -27,6 +34,7 @@
|
||||
#include "dissect-image.h"
|
||||
#include "dm-util.h"
|
||||
#include "env-file.h"
|
||||
#include "env-util.h"
|
||||
#include "extension-release.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
@ -42,6 +50,7 @@
|
||||
#include "mountpoint-util.h"
|
||||
#include "namespace-util.h"
|
||||
#include "nulstr-util.h"
|
||||
#include "openssl-util.h"
|
||||
#include "os-util.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
@ -807,6 +816,10 @@ int dissect_image(
|
||||
verity->root_hash &&
|
||||
(verity->designator < 0 || verity->designator == PARTITION_ROOT);
|
||||
|
||||
m->has_verity_sig = false; /* signature not embedded, must be specified */
|
||||
m->verity_sig_ready = m->verity_ready &&
|
||||
verity->root_hash_sig;
|
||||
|
||||
options = mount_options_from_designator(mount_options, PARTITION_ROOT);
|
||||
if (options) {
|
||||
o = strdup(options);
|
||||
@ -822,6 +835,8 @@ int dissect_image(
|
||||
.fstype = TAKE_PTR(t),
|
||||
.node = TAKE_PTR(n),
|
||||
.mount_options = TAKE_PTR(o),
|
||||
.offset = 0,
|
||||
.size = UINT64_MAX,
|
||||
};
|
||||
|
||||
*ret = TAKE_PTR(m);
|
||||
@ -865,6 +880,7 @@ int dissect_image(
|
||||
for (int i = 0; i < n_partitions; i++) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *q = NULL;
|
||||
unsigned long long pflags;
|
||||
blkid_loff_t start, size;
|
||||
blkid_partition pp;
|
||||
const char *node;
|
||||
int nr;
|
||||
@ -889,6 +905,20 @@ int dissect_image(
|
||||
if (nr < 0)
|
||||
return errno_or_else(EIO);
|
||||
|
||||
errno = 0;
|
||||
start = blkid_partition_get_start(pp);
|
||||
if (start < 0)
|
||||
return errno_or_else(EIO);
|
||||
|
||||
assert((uint64_t) start < UINT64_MAX/512);
|
||||
|
||||
errno = 0;
|
||||
size = blkid_partition_get_size(pp);
|
||||
if (size < 0)
|
||||
return errno_or_else(EIO);
|
||||
|
||||
assert((uint64_t) size < UINT64_MAX/512);
|
||||
|
||||
if (is_gpt) {
|
||||
PartitionDesignator designator = _PARTITION_DESIGNATOR_INVALID;
|
||||
int architecture = _ARCHITECTURE_INVALID;
|
||||
@ -982,14 +1012,42 @@ int dissect_image(
|
||||
|
||||
m->has_verity = true;
|
||||
|
||||
/* Ignore verity unless a root hash is specified */
|
||||
if (sd_id128_is_null(root_verity_uuid) || !sd_id128_equal(root_verity_uuid, id))
|
||||
/* If no verity configuration is specified, then don't do verity */
|
||||
if (!verity)
|
||||
continue;
|
||||
if (verity->designator >= 0 && verity->designator != PARTITION_ROOT)
|
||||
continue;
|
||||
|
||||
/* If root hash is specified, then ignore everything but the root id */
|
||||
if (!sd_id128_is_null(root_verity_uuid) && !sd_id128_equal(root_verity_uuid, id))
|
||||
continue;
|
||||
|
||||
designator = PARTITION_ROOT_VERITY;
|
||||
fstype = "DM_verity_hash";
|
||||
architecture = native_architecture();
|
||||
rw = false;
|
||||
|
||||
} else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE_VERITY_SIG)) {
|
||||
|
||||
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
|
||||
|
||||
if (pflags & GPT_FLAG_NO_AUTO)
|
||||
continue;
|
||||
|
||||
m->has_verity_sig = true;
|
||||
|
||||
/* If root hash is specified explicitly, then ignore any embedded signature */
|
||||
if (!verity)
|
||||
continue;
|
||||
if (verity->designator >= 0 && verity->designator != PARTITION_ROOT)
|
||||
continue;
|
||||
if (verity->root_hash)
|
||||
continue;
|
||||
|
||||
designator = PARTITION_ROOT_VERITY_SIG;
|
||||
fstype = "verity_hash_signature";
|
||||
architecture = native_architecture();
|
||||
rw = false;
|
||||
}
|
||||
#endif
|
||||
#ifdef GPT_ROOT_SECONDARY
|
||||
@ -1018,14 +1076,42 @@ int dissect_image(
|
||||
|
||||
m->has_verity = true;
|
||||
|
||||
/* Ignore verity unless root has is specified */
|
||||
if (sd_id128_is_null(root_verity_uuid) || !sd_id128_equal(root_verity_uuid, id))
|
||||
/* Don't do verity if no verity config is passed in */
|
||||
if (!verity)
|
||||
continue;
|
||||
if (verity->designator >= 0 && verity->designator != PARTITION_ROOT)
|
||||
continue;
|
||||
|
||||
/* If root hash is specified, then ignore everything but the root id */
|
||||
if (!sd_id128_is_null(root_verity_uuid) && !sd_id128_equal(root_verity_uuid, id))
|
||||
continue;
|
||||
|
||||
designator = PARTITION_ROOT_SECONDARY_VERITY;
|
||||
fstype = "DM_verity_hash";
|
||||
architecture = SECONDARY_ARCHITECTURE;
|
||||
rw = false;
|
||||
|
||||
} else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY_VERITY_SIG)) {
|
||||
|
||||
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
|
||||
|
||||
if (pflags & GPT_FLAG_NO_AUTO)
|
||||
continue;
|
||||
|
||||
m->has_verity_sig = true;
|
||||
|
||||
/* If root hash is specified explicitly, then ignore any embedded signature */
|
||||
if (!verity)
|
||||
continue;
|
||||
if (verity->designator >= 0 && verity->designator != PARTITION_ROOT)
|
||||
continue;
|
||||
if (verity->root_hash)
|
||||
continue;
|
||||
|
||||
designator = PARTITION_ROOT_SECONDARY_VERITY_SIG;
|
||||
fstype = "verity_hash_signature";
|
||||
architecture = native_architecture();
|
||||
rw = false;
|
||||
}
|
||||
#endif
|
||||
#ifdef GPT_USR_NATIVE
|
||||
@ -1054,14 +1140,41 @@ int dissect_image(
|
||||
|
||||
m->has_verity = true;
|
||||
|
||||
/* Ignore verity unless a usr hash is specified */
|
||||
if (sd_id128_is_null(usr_verity_uuid) || !sd_id128_equal(usr_verity_uuid, id))
|
||||
if (!verity)
|
||||
continue;
|
||||
if (verity->designator >= 0 && verity->designator != PARTITION_USR)
|
||||
continue;
|
||||
|
||||
/* If usr hash is specified, then ignore everything but the usr id */
|
||||
if (!sd_id128_is_null(usr_verity_uuid) && !sd_id128_equal(usr_verity_uuid, id))
|
||||
continue;
|
||||
|
||||
designator = PARTITION_USR_VERITY;
|
||||
fstype = "DM_verity_hash";
|
||||
architecture = native_architecture();
|
||||
rw = false;
|
||||
|
||||
} else if (sd_id128_equal(type_id, GPT_USR_NATIVE_VERITY_SIG)) {
|
||||
|
||||
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
|
||||
|
||||
if (pflags & GPT_FLAG_NO_AUTO)
|
||||
continue;
|
||||
|
||||
m->has_verity_sig = true;
|
||||
|
||||
/* If usr hash is specified explicitly, then ignore any embedded signature */
|
||||
if (!verity)
|
||||
continue;
|
||||
if (verity->designator >= 0 && verity->designator != PARTITION_USR)
|
||||
continue;
|
||||
if (verity->root_hash)
|
||||
continue;
|
||||
|
||||
designator = PARTITION_USR_VERITY_SIG;
|
||||
fstype = "verity_hash_signature";
|
||||
architecture = native_architecture();
|
||||
rw = false;
|
||||
}
|
||||
#endif
|
||||
#ifdef GPT_USR_SECONDARY
|
||||
@ -1090,14 +1203,41 @@ int dissect_image(
|
||||
|
||||
m->has_verity = true;
|
||||
|
||||
/* Ignore verity unless usr has is specified */
|
||||
if (sd_id128_is_null(usr_verity_uuid) || !sd_id128_equal(usr_verity_uuid, id))
|
||||
if (!verity)
|
||||
continue;
|
||||
if (verity->designator >= 0 && verity->designator != PARTITION_USR)
|
||||
continue;
|
||||
|
||||
/* If usr hash is specified, then ignore everything but the root id */
|
||||
if (!sd_id128_is_null(usr_verity_uuid) && !sd_id128_equal(usr_verity_uuid, id))
|
||||
continue;
|
||||
|
||||
designator = PARTITION_USR_SECONDARY_VERITY;
|
||||
fstype = "DM_verity_hash";
|
||||
architecture = SECONDARY_ARCHITECTURE;
|
||||
rw = false;
|
||||
|
||||
} else if (sd_id128_equal(type_id, GPT_USR_SECONDARY_VERITY_SIG)) {
|
||||
|
||||
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
|
||||
|
||||
if (pflags & GPT_FLAG_NO_AUTO)
|
||||
continue;
|
||||
|
||||
m->has_verity_sig = true;
|
||||
|
||||
/* If usr hash is specified explicitly, then ignore any embedded signature */
|
||||
if (!verity)
|
||||
continue;
|
||||
if (verity->designator >= 0 && verity->designator != PARTITION_USR)
|
||||
continue;
|
||||
if (verity->root_hash)
|
||||
continue;
|
||||
|
||||
designator = PARTITION_USR_SECONDARY_VERITY_SIG;
|
||||
fstype = "verity_hash_signature";
|
||||
architecture = native_architecture();
|
||||
rw = false;
|
||||
}
|
||||
#endif
|
||||
else if (sd_id128_equal(type_id, GPT_SWAP)) {
|
||||
@ -1223,6 +1363,8 @@ int dissect_image(
|
||||
.label = TAKE_PTR(l),
|
||||
.uuid = id,
|
||||
.mount_options = TAKE_PTR(o),
|
||||
.offset = (uint64_t) start * 512,
|
||||
.size = (uint64_t) size * 512,
|
||||
};
|
||||
}
|
||||
|
||||
@ -1281,6 +1423,8 @@ int dissect_image(
|
||||
.node = TAKE_PTR(n),
|
||||
.uuid = id,
|
||||
.mount_options = TAKE_PTR(o),
|
||||
.offset = (uint64_t) start * 512,
|
||||
.size = (uint64_t) size * 512,
|
||||
};
|
||||
|
||||
break;
|
||||
@ -1293,10 +1437,13 @@ int dissect_image(
|
||||
* since we never want to mount the secondary arch in this case. */
|
||||
m->partitions[PARTITION_ROOT_SECONDARY].found = false;
|
||||
m->partitions[PARTITION_ROOT_SECONDARY_VERITY].found = false;
|
||||
m->partitions[PARTITION_ROOT_SECONDARY_VERITY_SIG].found = false;
|
||||
m->partitions[PARTITION_USR_SECONDARY].found = false;
|
||||
m->partitions[PARTITION_USR_SECONDARY_VERITY].found = false;
|
||||
m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG].found = false;
|
||||
|
||||
} else if (m->partitions[PARTITION_ROOT_VERITY].found)
|
||||
} else if (m->partitions[PARTITION_ROOT_VERITY].found ||
|
||||
m->partitions[PARTITION_ROOT_VERITY_SIG].found)
|
||||
return -EADDRNOTAVAIL; /* Verity found but no matching rootfs? Something is off, refuse. */
|
||||
|
||||
else if (m->partitions[PARTITION_ROOT_SECONDARY].found) {
|
||||
@ -1308,22 +1455,32 @@ int dissect_image(
|
||||
zero(m->partitions[PARTITION_ROOT_SECONDARY]);
|
||||
m->partitions[PARTITION_ROOT_VERITY] = m->partitions[PARTITION_ROOT_SECONDARY_VERITY];
|
||||
zero(m->partitions[PARTITION_ROOT_SECONDARY_VERITY]);
|
||||
m->partitions[PARTITION_ROOT_VERITY_SIG] = m->partitions[PARTITION_ROOT_SECONDARY_VERITY_SIG];
|
||||
zero(m->partitions[PARTITION_ROOT_SECONDARY_VERITY_SIG]);
|
||||
|
||||
m->partitions[PARTITION_USR] = m->partitions[PARTITION_USR_SECONDARY];
|
||||
zero(m->partitions[PARTITION_USR_SECONDARY]);
|
||||
m->partitions[PARTITION_USR_VERITY] = m->partitions[PARTITION_USR_SECONDARY_VERITY];
|
||||
zero(m->partitions[PARTITION_USR_SECONDARY_VERITY]);
|
||||
m->partitions[PARTITION_USR_VERITY_SIG] = m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG];
|
||||
zero(m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG]);
|
||||
|
||||
} else if (m->partitions[PARTITION_ROOT_SECONDARY_VERITY].found)
|
||||
} else if (m->partitions[PARTITION_ROOT_SECONDARY_VERITY].found ||
|
||||
m->partitions[PARTITION_ROOT_SECONDARY_VERITY_SIG].found)
|
||||
return -EADDRNOTAVAIL; /* as above */
|
||||
|
||||
if (m->partitions[PARTITION_USR].found) {
|
||||
/* Hmm, we found a signature partition but no Verity data? Something is off. */
|
||||
if (m->partitions[PARTITION_ROOT_VERITY_SIG].found && !m->partitions[PARTITION_ROOT_VERITY].found)
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
if (m->partitions[PARTITION_USR].found) {
|
||||
/* Invalidate secondary arch /usr/ if we found the primary arch */
|
||||
m->partitions[PARTITION_USR_SECONDARY].found = false;
|
||||
m->partitions[PARTITION_USR_SECONDARY_VERITY].found = false;
|
||||
m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG].found = false;
|
||||
|
||||
} else if (m->partitions[PARTITION_USR_VERITY].found)
|
||||
} else if (m->partitions[PARTITION_USR_VERITY].found ||
|
||||
m->partitions[PARTITION_USR_VERITY_SIG].found)
|
||||
return -EADDRNOTAVAIL; /* as above */
|
||||
|
||||
else if (m->partitions[PARTITION_USR_SECONDARY].found) {
|
||||
@ -1333,10 +1490,17 @@ int dissect_image(
|
||||
zero(m->partitions[PARTITION_USR_SECONDARY]);
|
||||
m->partitions[PARTITION_USR_VERITY] = m->partitions[PARTITION_USR_SECONDARY_VERITY];
|
||||
zero(m->partitions[PARTITION_USR_SECONDARY_VERITY]);
|
||||
m->partitions[PARTITION_USR_VERITY_SIG] = m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG];
|
||||
zero(m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG]);
|
||||
|
||||
} else if (m->partitions[PARTITION_USR_SECONDARY_VERITY].found)
|
||||
} else if (m->partitions[PARTITION_USR_SECONDARY_VERITY].found ||
|
||||
m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG].found)
|
||||
return -EADDRNOTAVAIL; /* as above */
|
||||
|
||||
/* Hmm, we found a signature partition but no Verity data? Something is off. */
|
||||
if (m->partitions[PARTITION_USR_VERITY_SIG].found && !m->partitions[PARTITION_USR_VERITY].found)
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
/* If root and /usr are combined then insist that the architecture matches */
|
||||
if (m->partitions[PARTITION_ROOT].found &&
|
||||
m->partitions[PARTITION_USR].found &&
|
||||
@ -1381,6 +1545,8 @@ int dissect_image(
|
||||
.node = TAKE_PTR(generic_node),
|
||||
.uuid = generic_uuid,
|
||||
.mount_options = TAKE_PTR(o),
|
||||
.offset = UINT64_MAX,
|
||||
.size = UINT64_MAX,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1407,6 +1573,9 @@ int dissect_image(
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
if (verity->root_hash) {
|
||||
/* If we have an explicit root hash and found the partitions for it, then we are ready to use
|
||||
* Verity, set things up for it */
|
||||
|
||||
if (verity->designator < 0 || verity->designator == PARTITION_ROOT) {
|
||||
if (!m->partitions[PARTITION_ROOT_VERITY].found || !m->partitions[PARTITION_ROOT].found)
|
||||
return -EADDRNOTAVAIL;
|
||||
@ -1424,6 +1593,16 @@ int dissect_image(
|
||||
m->partitions[PARTITION_USR].rw = false;
|
||||
m->verity_ready = true;
|
||||
}
|
||||
|
||||
if (m->verity_ready)
|
||||
m->verity_sig_ready = !!verity->root_hash_sig;
|
||||
|
||||
} else if (m->partitions[verity->designator == PARTITION_USR ? PARTITION_USR_VERITY_SIG : PARTITION_ROOT_VERITY_SIG].found) {
|
||||
|
||||
/* If we found an embedded signature partition, we are ready, too. */
|
||||
|
||||
m->verity_ready = m->verity_sig_ready = true;
|
||||
m->partitions[verity->designator == PARTITION_USR ? PARTITION_USR : PARTITION_ROOT].rw = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2088,6 +2267,146 @@ static inline char* dm_deferred_remove_clean(char *name) {
|
||||
}
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(char *, dm_deferred_remove_clean);
|
||||
|
||||
static int validate_signature_userspace(const VeritySettings *verity) {
|
||||
#if HAVE_OPENSSL
|
||||
_cleanup_(sk_X509_free_allp) STACK_OF(X509) *sk = NULL;
|
||||
_cleanup_strv_free_ char **certs = NULL;
|
||||
_cleanup_(PKCS7_freep) PKCS7 *p7 = NULL;
|
||||
_cleanup_free_ char *s = NULL;
|
||||
_cleanup_(BIO_freep) BIO *bio = NULL; /* 'bio' must be freed first, 's' second, hence keep this order
|
||||
* of declaration in place, please */
|
||||
const unsigned char *d;
|
||||
char **i;
|
||||
int r;
|
||||
|
||||
assert(verity);
|
||||
assert(verity->root_hash);
|
||||
assert(verity->root_hash_sig);
|
||||
|
||||
/* Because installing a signature certificate into the kernel chain is so messy, let's optionally do
|
||||
* userspace validation. */
|
||||
|
||||
r = conf_files_list_nulstr(&certs, ".crt", NULL, CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, CONF_PATHS_NULSTR("verity.d"));
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to enumerate certificates: %m");
|
||||
if (strv_isempty(certs)) {
|
||||
log_debug("No userspace dm-verity certificates found.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
d = verity->root_hash_sig;
|
||||
p7 = d2i_PKCS7(NULL, &d, (long) verity->root_hash_sig_size);
|
||||
if (!p7)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse PKCS7 DER signature data.");
|
||||
|
||||
s = hexmem(verity->root_hash, verity->root_hash_size);
|
||||
if (!s)
|
||||
return log_oom_debug();
|
||||
|
||||
bio = BIO_new_mem_buf(s, strlen(s));
|
||||
if (!bio)
|
||||
return log_oom_debug();
|
||||
|
||||
sk = sk_X509_new_null();
|
||||
if (!sk)
|
||||
return log_oom_debug();
|
||||
|
||||
STRV_FOREACH(i, certs) {
|
||||
_cleanup_(X509_freep) X509 *c = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
|
||||
f = fopen(*i, "re");
|
||||
if (!f) {
|
||||
log_debug_errno(errno, "Failed to open '%s', ignoring: %m", *i);
|
||||
continue;
|
||||
}
|
||||
|
||||
c = PEM_read_X509(f, NULL, NULL, NULL);
|
||||
if (!c) {
|
||||
log_debug("Failed to load X509 certificate '%s', ignoring.", *i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sk_X509_push(sk, c) == 0)
|
||||
return log_oom_debug();
|
||||
|
||||
TAKE_PTR(c);
|
||||
}
|
||||
|
||||
r = PKCS7_verify(p7, sk, NULL, bio, NULL, PKCS7_NOINTERN|PKCS7_NOVERIFY);
|
||||
if (r)
|
||||
log_debug("Userspace PKCS#7 validation succeeded.");
|
||||
else
|
||||
log_debug("Userspace PKCS#7 validation failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
|
||||
return r;
|
||||
#else
|
||||
log_debug("Not doing client-side validation of dm-verity root hash signatures, OpenSSL support disabled.");
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int do_crypt_activate_verity(
|
||||
struct crypt_device *cd,
|
||||
const char *name,
|
||||
const VeritySettings *verity) {
|
||||
|
||||
bool check_signature;
|
||||
int r;
|
||||
|
||||
assert(cd);
|
||||
assert(name);
|
||||
assert(verity);
|
||||
|
||||
if (verity->root_hash_sig) {
|
||||
r = getenv_bool_secure("SYSTEMD_DISSECT_VERITY_SIGNATURE");
|
||||
if (r < 0 && r != -ENXIO)
|
||||
log_debug_errno(r, "Failed to parse $SYSTEMD_DISSECT_VERITY_SIGNATURE");
|
||||
|
||||
check_signature = r != 0;
|
||||
} else
|
||||
check_signature = false;
|
||||
|
||||
if (check_signature) {
|
||||
|
||||
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
|
||||
/* First, if we have support for signed keys in the kernel, then try that first. */
|
||||
r = sym_crypt_activate_by_signed_key(
|
||||
cd,
|
||||
name,
|
||||
verity->root_hash,
|
||||
verity->root_hash_size,
|
||||
verity->root_hash_sig,
|
||||
verity->root_hash_sig_size,
|
||||
CRYPT_ACTIVATE_READONLY);
|
||||
if (r >= 0)
|
||||
return r;
|
||||
|
||||
log_debug("Validation of dm-verity signature failed via the kernel, trying userspace validation instead.");
|
||||
#else
|
||||
log_debug("Activation of verity device with signature requested, but not supported via the kernel by %s due to missing crypt_activate_by_signed_key(), trying userspace validation instead.",
|
||||
program_invocation_short_name);
|
||||
#endif
|
||||
|
||||
/* So this didn't work via the kernel, then let's try userspace validation instead. If that
|
||||
* works we'll try to activate without telling the kernel the signature. */
|
||||
|
||||
r = validate_signature_userspace(verity);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(ENOKEY),
|
||||
"Activation of signed Verity volume worked neither via the kernel nor in userspace, can't activate.");
|
||||
}
|
||||
|
||||
return sym_crypt_activate_by_volume_key(
|
||||
cd,
|
||||
name,
|
||||
verity->root_hash,
|
||||
verity->root_hash_size,
|
||||
CRYPT_ACTIVATE_READONLY);
|
||||
}
|
||||
|
||||
static int verity_partition(
|
||||
PartitionDesignator designator,
|
||||
DissectedPartition *m,
|
||||
@ -2159,27 +2478,8 @@ static int verity_partition(
|
||||
* In case of ENODEV/ENOENT, which can happen if another process is activating at the exact same time,
|
||||
* retry a few times before giving up. */
|
||||
for (unsigned i = 0; i < N_DEVICE_NODE_LIST_ATTEMPTS; i++) {
|
||||
if (verity->root_hash_sig) {
|
||||
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
|
||||
r = sym_crypt_activate_by_signed_key(
|
||||
cd,
|
||||
name,
|
||||
verity->root_hash,
|
||||
verity->root_hash_size,
|
||||
verity->root_hash_sig,
|
||||
verity->root_hash_sig_size,
|
||||
CRYPT_ACTIVATE_READONLY);
|
||||
#else
|
||||
r = log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"Activation of verity device with signature requested, but not supported by %s due to missing crypt_activate_by_signed_key().", program_invocation_short_name);
|
||||
#endif
|
||||
} else
|
||||
r = sym_crypt_activate_by_volume_key(
|
||||
cd,
|
||||
name,
|
||||
verity->root_hash,
|
||||
verity->root_hash_size,
|
||||
CRYPT_ACTIVATE_READONLY);
|
||||
|
||||
r = do_crypt_activate_verity(cd, name, verity);
|
||||
/* libdevmapper can return EINVAL when the device is already in the activation stage.
|
||||
* There's no way to distinguish this situation from a genuine error due to invalid
|
||||
* parameters, so immediately fall back to activating the device with a unique name.
|
||||
@ -2438,6 +2738,12 @@ int verity_settings_load(
|
||||
if (is_device_path(image))
|
||||
return 0;
|
||||
|
||||
r = getenv_bool_secure("SYSTEMD_DISSECT_VERITY_SIDECAR");
|
||||
if (r < 0 && r != -ENXIO)
|
||||
log_debug_errno(r, "Failed to parse $SYSTEMD_DISSECT_VERITY_SIDECAR, ignoring: %m");
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
designator = verity->designator;
|
||||
|
||||
/* We only fill in what isn't already filled in */
|
||||
@ -2594,6 +2900,109 @@ int verity_settings_load(
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dissected_image_load_verity_sig_partition(
|
||||
DissectedImage *m,
|
||||
int fd,
|
||||
VeritySettings *verity) {
|
||||
|
||||
_cleanup_free_ void *root_hash = NULL, *root_hash_sig = NULL;
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
size_t root_hash_size, root_hash_sig_size;
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
PartitionDesignator d;
|
||||
DissectedPartition *p;
|
||||
JsonVariant *rh, *sig;
|
||||
ssize_t n;
|
||||
char *e;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(fd >= 0);
|
||||
assert(verity);
|
||||
|
||||
if (verity->root_hash && verity->root_hash_sig) /* Already loaded? */
|
||||
return 0;
|
||||
|
||||
r = getenv_bool_secure("SYSTEMD_DISSECT_VERITY_EMBEDDED");
|
||||
if (r < 0 && r != -ENXIO)
|
||||
log_debug_errno(r, "Failed to parse $SYSTEMD_DISSECT_VERITY_EMBEDDED, ignoring: %m");
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
d = PARTITION_VERITY_SIG_OF(verity->designator < 0 ? PARTITION_ROOT : verity->designator);
|
||||
assert(d >= 0);
|
||||
|
||||
p = m->partitions + d;
|
||||
if (!p->found)
|
||||
return 0;
|
||||
if (p->offset == UINT64_MAX || p->size == UINT64_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (p->size > 4*1024*1024) /* Signature data cannot possible be larger than 4M, refuse that */
|
||||
return -EFBIG;
|
||||
|
||||
buf = new(char, p->size+1);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
n = pread(fd, buf, p->size, p->offset);
|
||||
if (n < 0)
|
||||
return -ENOMEM;
|
||||
if ((uint64_t) n != p->size)
|
||||
return -EIO;
|
||||
|
||||
e = memchr(buf, 0, p->size);
|
||||
if (e) {
|
||||
/* If we found a NUL byte then the rest of the data must be NUL too */
|
||||
if (!memeqzero(e, p->size - (e - buf)))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Signature data contains embedded NUL byte.");
|
||||
} else
|
||||
buf[p->size] = 0;
|
||||
|
||||
r = json_parse(buf, 0, &v, NULL, NULL);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse signature JSON data: %m");
|
||||
|
||||
rh = json_variant_by_key(v, "rootHash");
|
||||
if (!rh)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Signature JSON object lacks 'rootHash' field.");
|
||||
if (!json_variant_is_string(rh))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "'rootHash' field of signature JSON object is not a string.");
|
||||
|
||||
r = unhexmem(json_variant_string(rh), SIZE_MAX, &root_hash, &root_hash_size);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse root hash field: %m");
|
||||
|
||||
/* Check if specified root hash matches if it is specified */
|
||||
if (verity->root_hash &&
|
||||
memcmp_nn(verity->root_hash, verity->root_hash_size, root_hash, root_hash_size) != 0) {
|
||||
_cleanup_free_ char *a = NULL, *b = NULL;
|
||||
|
||||
a = hexmem(root_hash, root_hash_size);
|
||||
b = hexmem(verity->root_hash, verity->root_hash_size);
|
||||
|
||||
return log_debug_errno(r, "Root hash in signature JSON data (%s) doesn't match configured hash (%s).", strna(a), strna(b));
|
||||
}
|
||||
|
||||
sig = json_variant_by_key(v, "signature");
|
||||
if (!sig)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Signature JSON object lacks 'signature' field.");
|
||||
if (!json_variant_is_string(sig))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "'signature' field of signature JSON object is not a string.");
|
||||
|
||||
r = unbase64mem(json_variant_string(sig), SIZE_MAX, &root_hash_sig, &root_hash_sig_size);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse signature field: %m");
|
||||
|
||||
free_and_replace(verity->root_hash, root_hash);
|
||||
verity->root_hash_size = root_hash_size;
|
||||
|
||||
free_and_replace(verity->root_hash_sig, root_hash_sig);
|
||||
verity->root_hash_sig_size = root_hash_sig_size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dissected_image_acquire_metadata(DissectedImage *m) {
|
||||
|
||||
enum {
|
||||
@ -2901,6 +3310,23 @@ bool dissected_image_verity_ready(const DissectedImage *image, PartitionDesignat
|
||||
return k >= 0 && image->partitions[k].found;
|
||||
}
|
||||
|
||||
bool dissected_image_verity_sig_ready(const DissectedImage *image, PartitionDesignator partition_designator) {
|
||||
PartitionDesignator k;
|
||||
|
||||
assert(image);
|
||||
|
||||
/* Checks if this partition has verity signature data available that we can use. */
|
||||
|
||||
if (!image->verity_sig_ready)
|
||||
return false;
|
||||
|
||||
if (image->single_file_system)
|
||||
return partition_designator == PARTITION_ROOT;
|
||||
|
||||
k = PARTITION_VERITY_SIG_OF(partition_designator);
|
||||
return k >= 0 && image->partitions[k].found;
|
||||
}
|
||||
|
||||
MountOptions* mount_options_free_all(MountOptions *options) {
|
||||
MountOptions *m;
|
||||
|
||||
@ -2967,6 +3393,10 @@ int mount_image_privately_interactively(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_load_verity_sig_partition(dissected_image, d->fd, &verity);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_decrypt_interactively(dissected_image, NULL, &verity, flags, &decrypted_image);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -3014,6 +3444,10 @@ static const char *const partition_designator_table[] = {
|
||||
[PARTITION_ROOT_SECONDARY_VERITY] = "root-secondary-verity",
|
||||
[PARTITION_USR_VERITY] = "usr-verity",
|
||||
[PARTITION_USR_SECONDARY_VERITY] = "usr-secondary-verity",
|
||||
[PARTITION_ROOT_VERITY_SIG] = "root-verity-sig",
|
||||
[PARTITION_ROOT_SECONDARY_VERITY_SIG] = "root-secondary-verity-sig",
|
||||
[PARTITION_USR_VERITY_SIG] = "usr-verity-sig",
|
||||
[PARTITION_USR_SECONDARY_VERITY_SIG] = "usr-secondary-verity-sig",
|
||||
[PARTITION_TMP] = "tmp",
|
||||
[PARTITION_VAR] = "var",
|
||||
};
|
||||
@ -3073,6 +3507,10 @@ int verity_dissect_and_mount(
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to dissect image: %m");
|
||||
|
||||
r = dissected_image_load_verity_sig_partition(dissected_image, loop_device->fd, &verity);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_decrypt(
|
||||
dissected_image,
|
||||
NULL,
|
||||
|
||||
@ -28,6 +28,8 @@ struct DissectedPartition {
|
||||
char *decrypted_node;
|
||||
char *decrypted_fstype;
|
||||
char *mount_options;
|
||||
uint64_t size;
|
||||
uint64_t offset;
|
||||
};
|
||||
|
||||
typedef enum PartitionDesignator {
|
||||
@ -44,6 +46,10 @@ typedef enum PartitionDesignator {
|
||||
PARTITION_ROOT_SECONDARY_VERITY, /* verity data for the PARTITION_ROOT_SECONDARY partition */
|
||||
PARTITION_USR_VERITY,
|
||||
PARTITION_USR_SECONDARY_VERITY,
|
||||
PARTITION_ROOT_VERITY_SIG, /* PKCS#7 signature for root hash for the PARTITION_ROOT partition */
|
||||
PARTITION_ROOT_SECONDARY_VERITY_SIG, /* ditto for the PARTITION_ROOT_SECONDARY partition */
|
||||
PARTITION_USR_VERITY_SIG,
|
||||
PARTITION_USR_SECONDARY_VERITY_SIG,
|
||||
PARTITION_TMP,
|
||||
PARTITION_VAR,
|
||||
_PARTITION_DESIGNATOR_MAX,
|
||||
@ -64,7 +70,11 @@ static inline bool PARTITION_DESIGNATOR_VERSIONED(PartitionDesignator d) {
|
||||
PARTITION_ROOT_VERITY,
|
||||
PARTITION_ROOT_SECONDARY_VERITY,
|
||||
PARTITION_USR_VERITY,
|
||||
PARTITION_USR_SECONDARY_VERITY);
|
||||
PARTITION_USR_SECONDARY_VERITY,
|
||||
PARTITION_ROOT_VERITY_SIG,
|
||||
PARTITION_ROOT_SECONDARY_VERITY_SIG,
|
||||
PARTITION_USR_VERITY_SIG,
|
||||
PARTITION_USR_SECONDARY_VERITY_SIG);
|
||||
}
|
||||
|
||||
static inline PartitionDesignator PARTITION_VERITY_OF(PartitionDesignator p) {
|
||||
@ -87,6 +97,26 @@ static inline PartitionDesignator PARTITION_VERITY_OF(PartitionDesignator p) {
|
||||
}
|
||||
}
|
||||
|
||||
static inline PartitionDesignator PARTITION_VERITY_SIG_OF(PartitionDesignator p) {
|
||||
switch (p) {
|
||||
|
||||
case PARTITION_ROOT:
|
||||
return PARTITION_ROOT_VERITY_SIG;
|
||||
|
||||
case PARTITION_ROOT_SECONDARY:
|
||||
return PARTITION_ROOT_SECONDARY_VERITY_SIG;
|
||||
|
||||
case PARTITION_USR:
|
||||
return PARTITION_USR_VERITY_SIG;
|
||||
|
||||
case PARTITION_USR_SECONDARY:
|
||||
return PARTITION_USR_SECONDARY_VERITY_SIG;
|
||||
|
||||
default:
|
||||
return _PARTITION_DESIGNATOR_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum DissectImageFlags {
|
||||
DISSECT_IMAGE_DEVICE_READ_ONLY = 1 << 0, /* Make device read-only */
|
||||
DISSECT_IMAGE_DISCARD_ON_LOOP = 1 << 1, /* Turn on "discard" if on a loop device and file system supports it */
|
||||
@ -119,11 +149,14 @@ typedef enum DissectImageFlags {
|
||||
struct DissectedImage {
|
||||
bool encrypted:1;
|
||||
bool has_verity:1; /* verity available in image, but not necessarily used */
|
||||
bool has_verity_sig:1; /* pkcs#7 signature embedded in image */
|
||||
bool verity_ready:1; /* verity available, fully specified and usable */
|
||||
bool verity_sig_ready:1; /* verity signature logic, fully specified and usable */
|
||||
bool single_file_system:1; /* MBR/GPT or single file system */
|
||||
|
||||
DissectedPartition partitions[_PARTITION_DESIGNATOR_MAX];
|
||||
|
||||
/* Meta information extracted from /etc/os-release and similar */
|
||||
char *image_name;
|
||||
char *hostname;
|
||||
sd_id128_t machine_id;
|
||||
@ -186,8 +219,11 @@ PartitionDesignator partition_designator_from_string(const char *name) _pure_;
|
||||
int verity_settings_load(VeritySettings *verity, const char *image, const char *root_hash_path, const char *root_hash_sig_path);
|
||||
void verity_settings_done(VeritySettings *verity);
|
||||
|
||||
int dissected_image_load_verity_sig_partition(DissectedImage *m, int fd, VeritySettings *verity);
|
||||
|
||||
bool dissected_image_verity_candidate(const DissectedImage *image, PartitionDesignator d);
|
||||
bool dissected_image_verity_ready(const DissectedImage *image, PartitionDesignator d);
|
||||
bool dissected_image_verity_sig_ready(const DissectedImage *image, PartitionDesignator d);
|
||||
|
||||
int mount_image_privately_interactively(const char *path, DissectImageFlags flags, char **ret_directory, LoopDevice **ret_loop_device, DecryptedImage **ret_decrypted_image);
|
||||
|
||||
|
||||
118
src/shared/gpt.c
118
src/shared/gpt.c
@ -5,63 +5,83 @@
|
||||
#include "utf8.h"
|
||||
|
||||
const GptPartitionType gpt_partition_type_table[] = {
|
||||
{ GPT_ROOT_X86, "root-x86" },
|
||||
{ GPT_ROOT_X86_VERITY, "root-x86-verity" },
|
||||
{ GPT_ROOT_X86_64, "root-x86-64" },
|
||||
{ GPT_ROOT_X86_64_VERITY, "root-x86-64-verity" },
|
||||
{ GPT_ROOT_ARM, "root-arm" },
|
||||
{ GPT_ROOT_ARM_VERITY, "root-arm-verity" },
|
||||
{ GPT_ROOT_ARM_64, "root-arm64" },
|
||||
{ GPT_ROOT_ARM_64_VERITY, "root-arm64-verity" },
|
||||
{ GPT_ROOT_IA64, "root-ia64" },
|
||||
{ GPT_ROOT_IA64_VERITY, "root-ia64-verity" },
|
||||
{ GPT_ROOT_LOONGARCH64, "root-loongarch64" },
|
||||
{ GPT_ROOT_LOONGARCH64_VERITY, "root-loongarch64-verity" },
|
||||
{ GPT_ROOT_RISCV32, "root-riscv32" },
|
||||
{ GPT_ROOT_RISCV32_VERITY, "root-riscv32-verity" },
|
||||
{ GPT_ROOT_RISCV64, "root-riscv64" },
|
||||
{ GPT_ROOT_RISCV64_VERITY, "root-riscv64-verity" },
|
||||
{ GPT_ROOT_X86, "root-x86" },
|
||||
{ GPT_ROOT_X86_VERITY, "root-x86-verity" },
|
||||
{ GPT_ROOT_X86_VERITY_SIG, "root-x86-verity-sig" },
|
||||
{ GPT_ROOT_X86_64, "root-x86-64" },
|
||||
{ GPT_ROOT_X86_64_VERITY, "root-x86-64-verity" },
|
||||
{ GPT_ROOT_X86_64_VERITY_SIG, "root-x86-64-verity-sig" },
|
||||
{ GPT_ROOT_ARM, "root-arm" },
|
||||
{ GPT_ROOT_ARM_VERITY, "root-arm-verity" },
|
||||
{ GPT_ROOT_ARM_VERITY_SIG, "root-arm-verity-sig" },
|
||||
{ GPT_ROOT_ARM_64, "root-arm64" },
|
||||
{ GPT_ROOT_ARM_64_VERITY, "root-arm64-verity" },
|
||||
{ GPT_ROOT_ARM_64_VERITY_SIG, "root-arm64-verity-sig" },
|
||||
{ GPT_ROOT_IA64, "root-ia64" },
|
||||
{ GPT_ROOT_IA64_VERITY, "root-ia64-verity" },
|
||||
{ GPT_ROOT_IA64_VERITY_SIG, "root-ia64-verity-sig" },
|
||||
{ GPT_ROOT_LOONGARCH64, "root-loongarch64" },
|
||||
{ GPT_ROOT_LOONGARCH64_VERITY, "root-loongarch64-verity" },
|
||||
{ GPT_ROOT_LOONGARCH64_VERITY_SIG, "root-loongarch64-verity-sig" },
|
||||
{ GPT_ROOT_RISCV32, "root-riscv32" },
|
||||
{ GPT_ROOT_RISCV32_VERITY, "root-riscv32-verity" },
|
||||
{ GPT_ROOT_RISCV32_VERITY_SIG, "root-riscv32-verity-sig" },
|
||||
{ GPT_ROOT_RISCV64, "root-riscv64" },
|
||||
{ GPT_ROOT_RISCV64_VERITY, "root-riscv64-verity" },
|
||||
{ GPT_ROOT_RISCV64_VERITY_SIG, "root-riscv64-verity-sig" },
|
||||
#ifdef GPT_ROOT_NATIVE
|
||||
{ GPT_ROOT_NATIVE, "root" },
|
||||
{ GPT_ROOT_NATIVE_VERITY, "root-verity" },
|
||||
{ GPT_ROOT_NATIVE, "root" },
|
||||
{ GPT_ROOT_NATIVE_VERITY, "root-verity" },
|
||||
{ GPT_ROOT_NATIVE_VERITY_SIG, "root-verity-sig" },
|
||||
#endif
|
||||
#ifdef GPT_ROOT_SECONDARY
|
||||
{ GPT_ROOT_SECONDARY, "root-secondary" },
|
||||
{ GPT_ROOT_SECONDARY_VERITY, "root-secondary-verity" },
|
||||
{ GPT_ROOT_SECONDARY, "root-secondary" },
|
||||
{ GPT_ROOT_SECONDARY_VERITY, "root-secondary-verity" },
|
||||
{ GPT_ROOT_SECONDARY_VERITY_SIG, "root-secondary-verity-sig" },
|
||||
#endif
|
||||
{ GPT_USR_X86, "usr-x86" },
|
||||
{ GPT_USR_X86_VERITY, "usr-x86-verity" },
|
||||
{ GPT_USR_X86_64, "usr-x86-64" },
|
||||
{ GPT_USR_X86_64_VERITY, "usr-x86-64-verity" },
|
||||
{ GPT_USR_ARM, "usr-arm" },
|
||||
{ GPT_USR_ARM_VERITY, "usr-arm-verity" },
|
||||
{ GPT_USR_ARM_64, "usr-arm64" },
|
||||
{ GPT_USR_ARM_64_VERITY, "usr-arm64-verity" },
|
||||
{ GPT_USR_IA64, "usr-ia64" },
|
||||
{ GPT_USR_IA64_VERITY, "usr-ia64-verity" },
|
||||
{ GPT_USR_LOONGARCH64, "usr-loongarch64" },
|
||||
{ GPT_USR_LOONGARCH64_VERITY, "usr-loongarch64-verity" },
|
||||
{ GPT_USR_RISCV32, "usr-riscv32" },
|
||||
{ GPT_USR_RISCV32_VERITY, "usr-riscv32-verity" },
|
||||
{ GPT_USR_RISCV64, "usr-riscv64" },
|
||||
{ GPT_USR_RISCV64_VERITY, "usr-riscv64-verity" },
|
||||
{ GPT_USR_X86, "usr-x86" },
|
||||
{ GPT_USR_X86_VERITY, "usr-x86-verity" },
|
||||
{ GPT_USR_X86_VERITY_SIG, "usr-x86-verity-sig" },
|
||||
{ GPT_USR_X86_64, "usr-x86-64" },
|
||||
{ GPT_USR_X86_64_VERITY, "usr-x86-64-verity" },
|
||||
{ GPT_USR_X86_64_VERITY_SIG, "usr-x86-64-verity-sig" },
|
||||
{ GPT_USR_ARM, "usr-arm" },
|
||||
{ GPT_USR_ARM_VERITY, "usr-arm-verity" },
|
||||
{ GPT_USR_ARM_VERITY_SIG, "usr-arm-verity-sig" },
|
||||
{ GPT_USR_ARM_64, "usr-arm64" },
|
||||
{ GPT_USR_ARM_64_VERITY, "usr-arm64-verity" },
|
||||
{ GPT_USR_ARM_64_VERITY_SIG, "usr-arm64-verity-sig" },
|
||||
{ GPT_USR_IA64, "usr-ia64" },
|
||||
{ GPT_USR_IA64_VERITY, "usr-ia64-verity" },
|
||||
{ GPT_USR_IA64_VERITY_SIG, "usr-ia64-verity-sig" },
|
||||
{ GPT_USR_LOONGARCH64, "usr-loongarch64" },
|
||||
{ GPT_USR_LOONGARCH64_VERITY, "usr-loongarch64-verity" },
|
||||
{ GPT_USR_LOONGARCH64_VERITY_SIG, "usr-loongarch64-verity-sig" },
|
||||
{ GPT_USR_RISCV32, "usr-riscv32" },
|
||||
{ GPT_USR_RISCV32_VERITY, "usr-riscv32-verity" },
|
||||
{ GPT_USR_RISCV32_VERITY_SIG, "usr-riscv32-verity-sig" },
|
||||
{ GPT_USR_RISCV64, "usr-riscv64" },
|
||||
{ GPT_USR_RISCV64_VERITY, "usr-riscv64-verity" },
|
||||
{ GPT_USR_RISCV64_VERITY_SIG, "usr-riscv64-verity-sig" },
|
||||
#ifdef GPT_USR_NATIVE
|
||||
{ GPT_USR_NATIVE, "usr" },
|
||||
{ GPT_USR_NATIVE_VERITY, "usr-verity" },
|
||||
{ GPT_USR_NATIVE, "usr" },
|
||||
{ GPT_USR_NATIVE_VERITY, "usr-verity" },
|
||||
{ GPT_USR_NATIVE_VERITY_SIG, "usr-verity-sig" },
|
||||
#endif
|
||||
#ifdef GPT_USR_SECONDARY
|
||||
{ GPT_USR_SECONDARY, "usr-secondary" },
|
||||
{ GPT_USR_SECONDARY_VERITY, "usr-secondary-verity" },
|
||||
{ GPT_USR_SECONDARY, "usr-secondary" },
|
||||
{ GPT_USR_SECONDARY_VERITY, "usr-secondary-verity" },
|
||||
{ GPT_USR_SECONDARY_VERITY_SIG, "usr-secondary-verity-sig" },
|
||||
#endif
|
||||
{ GPT_ESP, "esp" },
|
||||
{ GPT_XBOOTLDR, "xbootldr" },
|
||||
{ GPT_SWAP, "swap" },
|
||||
{ GPT_HOME, "home" },
|
||||
{ GPT_SRV, "srv" },
|
||||
{ GPT_VAR, "var" },
|
||||
{ GPT_TMP, "tmp" },
|
||||
{ GPT_USER_HOME, "user-home" },
|
||||
{ GPT_LINUX_GENERIC, "linux-generic" },
|
||||
{ GPT_ESP, "esp" },
|
||||
{ GPT_XBOOTLDR, "xbootldr" },
|
||||
{ GPT_SWAP, "swap" },
|
||||
{ GPT_HOME, "home" },
|
||||
{ GPT_SRV, "srv" },
|
||||
{ GPT_VAR, "var" },
|
||||
{ GPT_TMP, "tmp" },
|
||||
{ GPT_USER_HOME, "user-home" },
|
||||
{ GPT_LINUX_GENERIC, "linux-generic" },
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
@ -56,27 +56,53 @@
|
||||
#define GPT_USR_RISCV32_VERITY SD_ID128_MAKE(cb,1e,e4,e3,8c,d0,41,36,a0,a4,aa,61,a3,2e,87,30)
|
||||
#define GPT_USR_RISCV64_VERITY SD_ID128_MAKE(8f,10,56,be,9b,05,47,c4,81,d6,be,53,12,8e,5b,54)
|
||||
|
||||
/* PKCS#7 Signatures for the Verity Root Hashes */
|
||||
#define GPT_ROOT_X86_VERITY_SIG SD_ID128_MAKE(59,96,fc,05,10,9c,48,de,80,8b,23,fa,08,30,b6,76)
|
||||
#define GPT_ROOT_X86_64_VERITY_SIG SD_ID128_MAKE(41,09,2b,05,9f,c8,45,23,99,4f,2d,ef,04,08,b1,76)
|
||||
#define GPT_ROOT_ARM_VERITY_SIG SD_ID128_MAKE(42,b0,45,5f,eb,11,49,1d,98,d3,56,14,5b,a9,d0,37)
|
||||
#define GPT_ROOT_ARM_64_VERITY_SIG SD_ID128_MAKE(6d,b6,9d,e6,29,f4,47,58,a7,a5,96,21,90,f0,0c,e3)
|
||||
#define GPT_ROOT_IA64_VERITY_SIG SD_ID128_MAKE(e9,8b,36,ee,32,ba,48,82,9b,12,0c,e1,46,55,f4,6a)
|
||||
#define GPT_ROOT_LOONGARCH64_VERITY_SIG SD_ID128_MAKE(5a,fb,67,eb,ec,c8,4f,85,ae,8e,ac,1e,7c,50,e7,d0)
|
||||
#define GPT_ROOT_RISCV32_VERITY_SIG SD_ID128_MAKE(3a,11,2a,75,87,29,43,80,b4,cf,76,4d,79,93,44,48)
|
||||
#define GPT_ROOT_RISCV64_VERITY_SIG SD_ID128_MAKE(ef,e0,f0,87,ea,8d,44,69,82,1a,4c,2a,96,a8,38,6a)
|
||||
#define GPT_USR_X86_VERITY_SIG SD_ID128_MAKE(97,4a,71,c0,de,41,43,c3,be,5d,5c,5c,cd,1a,d2,c0)
|
||||
#define GPT_USR_X86_64_VERITY_SIG SD_ID128_MAKE(e7,bb,33,fb,06,cf,4e,81,82,73,e5,43,b4,13,e2,e2)
|
||||
#define GPT_USR_ARM_VERITY_SIG SD_ID128_MAKE(d7,ff,81,2f,37,d1,49,02,a8,10,d7,6b,a5,7b,97,5a)
|
||||
#define GPT_USR_ARM_64_VERITY_SIG SD_ID128_MAKE(c2,3c,e4,ff,44,bd,4b,00,b2,d4,b4,1b,34,19,e0,2a)
|
||||
#define GPT_USR_IA64_VERITY_SIG SD_ID128_MAKE(8d,e5,8b,c2,2a,43,46,0d,b1,4e,a7,6e,4a,17,b4,7f)
|
||||
#define GPT_USR_LOONGARCH64_VERITY_SIG SD_ID128_MAKE(b0,24,f3,15,d3,30,44,4c,84,61,44,bb,de,52,4e,99)
|
||||
#define GPT_USR_RISCV32_VERITY_SIG SD_ID128_MAKE(c3,83,6a,13,31,37,45,ba,b5,83,b1,6c,50,fe,5e,b4)
|
||||
#define GPT_USR_RISCV64_VERITY_SIG SD_ID128_MAKE(d2,f9,00,0a,7a,18,45,3f,b5,cd,4d,32,f7,7a,7b,32)
|
||||
|
||||
#if defined(__x86_64__)
|
||||
# define GPT_ROOT_NATIVE GPT_ROOT_X86_64
|
||||
# define GPT_ROOT_SECONDARY GPT_ROOT_X86
|
||||
# define GPT_ROOT_NATIVE_VERITY GPT_ROOT_X86_64_VERITY
|
||||
# define GPT_ROOT_SECONDARY_VERITY GPT_ROOT_X86_VERITY
|
||||
# define GPT_ROOT_NATIVE_VERITY_SIG GPT_ROOT_X86_64_VERITY_SIG
|
||||
# define GPT_ROOT_SECONDARY_VERITY_SIG GPT_ROOT_X86_VERITY_SIG
|
||||
# define GPT_USR_NATIVE GPT_USR_X86_64
|
||||
# define GPT_USR_SECONDARY GPT_USR_X86
|
||||
# define GPT_USR_NATIVE_VERITY GPT_USR_X86_64_VERITY
|
||||
# define GPT_USR_SECONDARY_VERITY GPT_USR_X86_VERITY
|
||||
# define GPT_USR_NATIVE_VERITY_SIG GPT_USR_X86_64_VERITY_SIG
|
||||
# define GPT_USR_SECONDARY_VERITY_SIG GPT_USR_X86_VERITY_SIG
|
||||
#elif defined(__i386__)
|
||||
# define GPT_ROOT_NATIVE GPT_ROOT_X86
|
||||
# define GPT_ROOT_NATIVE_VERITY GPT_ROOT_X86_VERITY
|
||||
# define GPT_ROOT_NATIVE_VERITY_SIG GPT_ROOT_X86_VERITY_SIG
|
||||
# define GPT_USR_NATIVE GPT_USR_X86
|
||||
# define GPT_USR_NATIVE_VERITY GPT_USR_X86_VERITY
|
||||
# define GPT_USR_NATIVE_VERITY_SIG GPT_USR_X86_VERITY_SIG
|
||||
#endif
|
||||
|
||||
#if defined(__ia64__)
|
||||
# define GPT_ROOT_NATIVE GPT_ROOT_IA64
|
||||
# define GPT_ROOT_NATIVE_VERITY GPT_ROOT_IA64_VERITY
|
||||
# define GPT_ROOT_NATIVE_VERITY_SIG GPT_ROOT_IA64_VERITY_SIG
|
||||
# define GPT_USR_NATIVE GPT_USR_IA64
|
||||
# define GPT_USR_NATIVE_VERITY GPT_USR_IA64_VERITY
|
||||
# define GPT_USR_NATIVE_VERITY_SIG GPT_USR_IA64_VERITY_SIG
|
||||
#endif
|
||||
|
||||
#if defined(__aarch64__) && (__BYTE_ORDER != __BIG_ENDIAN)
|
||||
@ -84,35 +110,47 @@
|
||||
# define GPT_ROOT_SECONDARY GPT_ROOT_ARM
|
||||
# define GPT_ROOT_NATIVE_VERITY GPT_ROOT_ARM_64_VERITY
|
||||
# define GPT_ROOT_SECONDARY_VERITY GPT_ROOT_ARM_VERITY
|
||||
# define GPT_ROOT_NATIVE_VERITY_SIG GPT_ROOT_ARM_64_VERITY_SIG
|
||||
# define GPT_ROOT_SECONDARY_VERITY_SIG GPT_ROOT_ARM_VERITY_SIG
|
||||
# define GPT_USR_NATIVE GPT_USR_ARM_64
|
||||
# define GPT_USR_SECONDARY GPT_USR_ARM
|
||||
# define GPT_USR_NATIVE_VERITY GPT_USR_ARM_64_VERITY
|
||||
# define GPT_USR_SECONDARY_VERITY GPT_USR_ARM_VERITY
|
||||
# define GPT_USR_NATIVE_VERITY_SIG GPT_USR_ARM_64_VERITY_SIG
|
||||
# define GPT_USR_SECONDARY_VERITY_SIG GPT_USR_ARM_VERITY_SIG
|
||||
#elif defined(__arm__) && (__BYTE_ORDER != __BIG_ENDIAN)
|
||||
# define GPT_ROOT_NATIVE GPT_ROOT_ARM
|
||||
# define GPT_ROOT_NATIVE_VERITY GPT_ROOT_ARM_VERITY
|
||||
# define GPT_ROOT_NATIVE_VERITY_SIG GPT_ROOT_ARM_VERITY_SIG
|
||||
# define GPT_USR_NATIVE GPT_USR_ARM
|
||||
# define GPT_USR_NATIVE_VERITY GPT_USR_ARM_VERITY
|
||||
# define GPT_USR_NATIVE_VERITY_SIG GPT_USR_ARM_VERITY_SIG
|
||||
#endif
|
||||
|
||||
#if defined(__loongarch64)
|
||||
# define GPT_ROOT_NATIVE GPT_ROOT_LOONGARCH64
|
||||
# define GPT_ROOT_NATIVE_VERITY GPT_ROOT_LOONGARCH64_VERITY
|
||||
# define GPT_ROOT_NATIVE_VERITY_SIG GPT_ROOT_LOONGARCH64_VERITY_SIG
|
||||
# define GPT_USR_NATIVE GPT_USR_LOONGARCH64
|
||||
# define GPT_USR_NATIVE_VERITY GPT_USR_LOONGARCH64_VERITY
|
||||
# define GPT_USR_NATIVE_VERITY_SIG GPT_USR_LOONGARCH64_VERITY_SIG
|
||||
#endif
|
||||
|
||||
#if defined(__riscv)
|
||||
#if (__riscv_xlen == 32)
|
||||
# define GPT_ROOT_NATIVE GPT_ROOT_RISCV32
|
||||
# define GPT_ROOT_NATIVE_VERITY GPT_ROOT_RISCV32_VERITY
|
||||
# define GPT_ROOT_NATIVE_VERITY_SIG GPT_ROOT_RISCV32_VERITY_SIG
|
||||
# define GPT_USR_NATIVE GPT_USR_RISCV32
|
||||
# define GPT_USR_NATIVE_VERITY GPT_USR_RISCV32_VERITY
|
||||
# define GPT_USR_NATIVE_VERITY_SIG GPT_USR_RISCV32_VERITY_SIG
|
||||
#elif (__riscv_xlen == 64)
|
||||
# define GPT_ROOT_NATIVE GPT_ROOT_RISCV64
|
||||
# define GPT_ROOT_NATIVE_VERITY GPT_ROOT_RISCV64_VERITY
|
||||
# define GPT_ROOT_NATIVE_VERITY_SIG GPT_ROOT_RISCV64_VERITY_SIG
|
||||
# define GPT_USR_NATIVE GPT_USR_RISCV64
|
||||
# define GPT_USR_NATIVE_VERITY GPT_USR_RISCV64_VERITY
|
||||
# define GPT_USR_NATIVE_VERITY_SIG GPT_USR_RISCV64_VERITY_SIG
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@ -4,13 +4,26 @@
|
||||
#include "macro.h"
|
||||
|
||||
#if HAVE_OPENSSL
|
||||
# include <openssl/bio.h>
|
||||
# include <openssl/evp.h>
|
||||
# include <openssl/x509.h>
|
||||
# include <openssl/pkcs7.h>
|
||||
# include <openssl/ssl.h>
|
||||
# include <openssl/x509v3.h>
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(X509*, X509_free, NULL);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(X509_NAME*, X509_NAME_free, NULL);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_PKEY_CTX*, EVP_PKEY_CTX_free, NULL);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_CIPHER_CTX*, EVP_CIPHER_CTX_free, NULL);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(PKCS7*, PKCS7_free, NULL);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(SSL*, SSL_free, NULL);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(BIO*, BIO_free, NULL);
|
||||
|
||||
static inline void sk_X509_free_allp(STACK_OF(X509) **sk) {
|
||||
if (!sk || !*sk)
|
||||
return;
|
||||
|
||||
sk_X509_pop_free(*sk, X509_free);
|
||||
}
|
||||
|
||||
int rsa_encrypt_bytes(EVP_PKEY *pkey, const void *decrypted_key, size_t decrypted_key_size, void **ret_encrypt_key, size_t *ret_encrypt_key_size);
|
||||
|
||||
|
||||
@ -540,6 +540,13 @@ static int merge_subprocess(Hashmap *images, const char *workspace) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_load_verity_sig_partition(
|
||||
m,
|
||||
d->fd,
|
||||
&verity_settings);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_decrypt_interactively(
|
||||
m, NULL,
|
||||
&verity_settings,
|
||||
|
||||
@ -14,6 +14,7 @@ TEST_INSTALL_VERITY_MINIMAL=1
|
||||
command -v mksquashfs >/dev/null 2>&1 || exit 0
|
||||
command -v veritysetup >/dev/null 2>&1 || exit 0
|
||||
command -v sfdisk >/dev/null 2>&1 || exit 0
|
||||
command -v openssl >/dev/null 2>&1 || exit 0
|
||||
|
||||
# Need loop devices for systemd-dissect
|
||||
test_append_files() {
|
||||
@ -26,6 +27,7 @@ test_append_files() {
|
||||
generate_module_dependencies
|
||||
inst_binary losetup
|
||||
inst_binary wc
|
||||
inst_binary openssl
|
||||
install_verity_minimal
|
||||
)
|
||||
}
|
||||
|
||||
@ -74,22 +74,27 @@ machine="$(uname -m)"
|
||||
if [ "${machine}" = "x86_64" ]; then
|
||||
root_guid=4f68bce3-e8cd-4db1-96e7-fbcaf984b709
|
||||
verity_guid=2c7357ed-ebd2-46d9-aec1-23d437ec2bf5
|
||||
signature_guid=41092b05-9fc8-4523-994f-2def0408b176
|
||||
architecture="x86-64"
|
||||
elif [ "${machine}" = "i386" ] || [ "${machine}" = "i686" ] || [ "${machine}" = "x86" ]; then
|
||||
root_guid=44479540-f297-41b2-9af7-d131d5f0458a
|
||||
verity_guid=d13c5d3b-b5d1-422a-b29f-9454fdc89d76
|
||||
signature_guid=5996fc05-109c-48de-808b-23fa0830b676
|
||||
architecture="x86"
|
||||
elif [ "${machine}" = "aarch64" ] || [ "${machine}" = "aarch64_be" ] || [ "${machine}" = "armv8b" ] || [ "${machine}" = "armv8l" ]; then
|
||||
root_guid=b921b045-1df0-41c3-af44-4c6f280d3fae
|
||||
verity_guid=df3300ce-d69f-4c92-978c-9bfb0f38d820
|
||||
signature_guid=6db69de6-29f4-4758-a7a5-962190f00ce3
|
||||
architecture="arm64"
|
||||
elif [ "${machine}" = "arm" ]; then
|
||||
root_guid=69dad710-2ce4-4e3c-b16c-21a1d49abed3
|
||||
verity_guid=7386cdf2-203c-47a9-a498-f2ecce45a2d6
|
||||
signature_guid=42b0455f-eb11-491d-98d3-56145ba9d037
|
||||
architecture="arm"
|
||||
elif [ "${machine}" = "ia64" ]; then
|
||||
root_guid=993d8d3d-f80e-4225-855a-9daf8ed7ea97
|
||||
verity_guid=86ed10d5-b607-45bb-8957-d350f23d0571
|
||||
signature_guid=e98b36ee-32ba-4882-9b12-0ce14655f46a
|
||||
architecture="ia64"
|
||||
elif [ "${machine}" = "ppc64le" ]; then
|
||||
# There's no support of PPC in the discoverable partitions specification yet, so skip the rest for now
|
||||
@ -102,8 +107,9 @@ fi
|
||||
# du rounds up to block size, which is more helpful for partitioning
|
||||
root_size="$(du -k "${image}.raw" | cut -f1)"
|
||||
verity_size="$(du -k "${image}.verity" | cut -f1)"
|
||||
signature_size=4
|
||||
# 4MB seems to be the minimum size blkid will accept, below that probing fails
|
||||
dd if=/dev/zero of="${image}.gpt" bs=512 count=$((8192+root_size*2+verity_size*2))
|
||||
dd if=/dev/zero of="${image}.gpt" bs=512 count=$((8192+root_size*2+verity_size*2+signature_size*2))
|
||||
# sfdisk seems unhappy if the size overflows into the next unit, eg: 1580KiB will be interpreted as 1MiB
|
||||
# so do some basic rounding up if the minimal image is more than 1 MB
|
||||
if [ "${root_size}" -ge 1024 ]; then
|
||||
@ -112,6 +118,36 @@ else
|
||||
root_size="${root_size}KiB"
|
||||
fi
|
||||
verity_size="$((verity_size * 2))KiB"
|
||||
signature_size="$((signature_size * 2))KiB"
|
||||
|
||||
# Unfortunately OpenSSL insists on reading some config file, hence provide one with mostly placeholder contents
|
||||
cat >> "${image}.openssl.cnf" <<EOF
|
||||
[ req ]
|
||||
prompt = no
|
||||
distinguished_name = req_distinguished_name
|
||||
|
||||
[ req_distinguished_name ]
|
||||
C = DE
|
||||
ST = Test State
|
||||
L = Test Locality
|
||||
O = Org Name
|
||||
OU = Org Unit Name
|
||||
CN = Common Name
|
||||
emailAddress = test@email.com
|
||||
EOF
|
||||
|
||||
# Create key pair
|
||||
openssl req -config "${image}.openssl.cnf" -new -x509 -newkey rsa:1024 -keyout "${image}.key" -out "${image}.crt" -days 365 -nodes
|
||||
# Sign Verity root hash with it
|
||||
openssl smime -sign -nocerts -noattr -binary -in "${image}.roothash" -inkey "${image}.key" -signer "${image}.crt" -outform der -out "${image}.roothash.p7s"
|
||||
# Generate signature partition JSON data
|
||||
echo '{"rootHash":"'"${roothash}"'","signature":"'"$(base64 -w 0 < "${image}.roothash.p7s")"'"}' > "${image}.verity-sig"
|
||||
# Pad it
|
||||
truncate -s "${signature_size}" "${image}.verity-sig"
|
||||
# Register certificate in the (userspace) verity key ring
|
||||
mkdir -p /run/verity.d
|
||||
ln -s "${image}.crt" /run/verity.d/ok.crt
|
||||
|
||||
# Construct a UUID from hash
|
||||
# input: 11111111222233334444555566667777
|
||||
# output: 11111111-2222-3333-4444-555566667777
|
||||
@ -119,11 +155,14 @@ uuid="$(head -c 32 "${image}.roothash" | sed -r 's/(.{8})(.{4})(.{4})(.{4})(.+)/
|
||||
echo -e "label: gpt\nsize=${root_size}, type=${root_guid}, uuid=${uuid}" | sfdisk "${image}.gpt"
|
||||
uuid="$(tail -c 32 "${image}.roothash" | sed -r 's/(.{8})(.{4})(.{4})(.{4})(.+)/\1-\2-\3-\4-\5/')"
|
||||
echo -e "size=${verity_size}, type=${verity_guid}, uuid=${uuid}" | sfdisk "${image}.gpt" --append
|
||||
echo -e "size=${signature_size}, type=${signature_guid}" | sfdisk "${image}.gpt" --append
|
||||
sfdisk --part-label "${image}.gpt" 1 "Root Partition"
|
||||
sfdisk --part-label "${image}.gpt" 2 "Verity Partition"
|
||||
sfdisk --part-label "${image}.gpt" 3 "Signature Partition"
|
||||
loop="$(losetup --show -P -f "${image}.gpt")"
|
||||
dd if="${image}.raw" of="${loop}p1"
|
||||
dd if="${image}.verity" of="${loop}p2"
|
||||
dd if="${image}.verity-sig" of="${loop}p3"
|
||||
losetup -d "${loop}"
|
||||
|
||||
# Derive partition UUIDs from root hash, in UUID syntax
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user