Merge pull request #17101 from poettering/gpt-usr
add gpt types for /usr/, similar to how we have it for root partitions
This commit is contained in:
commit
55e11ace68
3
TODO
3
TODO
|
@ -841,9 +841,6 @@ Features:
|
|||
|
||||
* add new gpt type for btrfs volumes
|
||||
|
||||
* support empty /etc boots nicely:
|
||||
- nspawn/gpt-generator: introduce new gpt partition type for /usr
|
||||
|
||||
* generator that automatically discovers btrfs subvolumes, identifies their purpose based on some xattr on them.
|
||||
|
||||
* a way for container managers to turn off getty starting via $container_headless= or so...
|
||||
|
|
|
@ -51,6 +51,16 @@ Interface](https://systemd.io/BOOT_LOADER_INTERFACE).
|
|||
| `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 |
|
||||
| `86ed10d5-b607-45bb-8957-d350f23d0571` | _Root Verity Partition (Itanium/IA-64)_ | 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 |
|
||||
| `b0e01050-ee5f-4390-949a-9101b17104e9` | _`/usr/` Partition (64-bit ARM/AArch64)_ | ditto | ditto |
|
||||
| `4301d2a6-4e3b-4b2a-bb94-9e0b2c4225ea` | _`/usr/` Partition (Itanium/IA-64)_ | ditto | ditto |
|
||||
| `8f461b0d-14ee-4e81-9aa9-049b6fb97abd` | _`/usr/` Verity Partition (x86)_ | Any native, optionally in LUKS | Similar semantics to root Verity partition, but just for the `/usr/` partition. |
|
||||
| `77ff5f63-e7b6-4633-acf4-1565b864c0e6` | _`/usr/` Verity Partition (x86-64)_ | ditto | ditto |
|
||||
| `c215d751-7bcd-4649-be90-6627490a4c05` | _`/usr/` Verity Partition (32-bit ARM)_ | ditto | ditto |
|
||||
| `6e11a4e7-fbca-4ded-b9e9-e1a512bb664e` | _`/usr/` Verity Partition (64-bit ARM/AArch64)_ | ditto | ditto |
|
||||
| `6a491e03-3be7-4545-8e38-83320e0ea880` | _`/usr/` Verity Partition (Itanium/IA-64)_ | 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 bit 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`. |
|
||||
|
@ -76,21 +86,21 @@ localized.
|
|||
|
||||
## Partition Flags
|
||||
|
||||
For the root, server data, home, variable data, temporary data and swap
|
||||
For the root, `/usr/`, server data, home, variable data, temporary data and swap
|
||||
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.
|
||||
|
||||
For the root, server data, home, variable data and temporary data 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.
|
||||
For the root, `/usr/` server data, home, variable data and temporary data
|
||||
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.
|
||||
|
||||
Note that these two flag definitions happen to map nicely to the ones used by
|
||||
Microsoft Basic Data Partitions.
|
||||
|
@ -104,8 +114,8 @@ An *installer* which supports a "manual partitioning" interface _may_ choose to
|
|||
pre-populate the interface with swap, `/home/`, `/srv/`, `/var/tmp/` partitions
|
||||
of pre-existing Linux installations, identified with the GPT type UUIDs
|
||||
above. The installer should not pre-populate such an interface with any
|
||||
identified root or `/var/` partition unless the intention is to overwrite an
|
||||
existing operating system that might be installed.
|
||||
identified root, `/usr` or `/var/` partition unless the intention is to
|
||||
overwrite an existing operating system that might be installed.
|
||||
|
||||
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
|
||||
|
@ -119,17 +129,17 @@ 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, `/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", "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.
|
||||
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
|
||||
scanning the disk containing the currently used EFI ESP. It _should_
|
||||
automatically discover and mount the first `/home/`, `/srv/`, `/var/`,
|
||||
automatically discover and mount the first `/usr/`, `/home/`, `/srv/`, `/var/`,
|
||||
`/var/tmp/` and swap partitions that do not have the no-auto flag set by
|
||||
scanning the disk containing the discovered root partition. It should
|
||||
automatically discover and mount the partition containing the currently used
|
||||
|
@ -138,19 +148,19 @@ and mount the partition containing the currently used Extended Boot Loader
|
|||
Partition to `/boot/`. It _should not_ discover or automatically mount
|
||||
partitions with other UUID partition types, or partitions located on other
|
||||
disks, or partitions with the no-auto flag set. User configuration shall
|
||||
always override automatic discovery and mounting. If a root, `/home/`,
|
||||
`/srv/`, `/boot/`, `/var/`, `/var/tmp/`, `/efi/`, `/boot/` or swap partition is
|
||||
listed in `/etc/fstab` or with `root=` on the kernel command line, it _must_
|
||||
take precedence over automatically discovered partitions. If a `/home/`,
|
||||
`/srv/`, `/boot/`, `/var/`, `/var/tmp/`, `/efi/` or `/boot/` directory is found
|
||||
to be populated already in the root partition, the automatic discovery _must
|
||||
not_ mount any discovered file system over it.
|
||||
always override automatic discovery and mounting. If a root, `/usr/`,
|
||||
`/home/`, `/srv/`, `/boot/`, `/var/`, `/var/tmp/`, `/efi/`, `/boot/` or swap
|
||||
partition is listed in `/etc/fstab` or with `root=` on the kernel command line,
|
||||
it _must_ take precedence over automatically discovered partitions. If a
|
||||
`/home/`, `/usr/`, `/srv/`, `/boot/`, `/var/`, `/var/tmp/`, `/efi/` or `/boot/`
|
||||
directory is found to be populated already in the root partition, the automatic
|
||||
discovery _must not_ mount any discovered file system over it.
|
||||
|
||||
A *container* *manager* should automatically discover and mount the root,
|
||||
`/home/`, `/srv/`, `/var/`, `/var/tmp/` partitions inside a container disk
|
||||
image. It may choose to mount any discovered ESP and/or XBOOOTLDR partition to
|
||||
`/efi/` or `/boot/`. It should ignore any swap should they be included in a
|
||||
container disk image.
|
||||
`/usr/`, `/home/`, `/srv/`, `/var/`, `/var/tmp/` partitions inside a container
|
||||
disk image. It may choose to mount any discovered ESP and/or XBOOOTLDR
|
||||
partition to `/efi/` or `/boot/`. It should ignore any swap should they be
|
||||
included in a container disk image.
|
||||
|
||||
If a btrfs file system is automatically discovered and mounted by the operating
|
||||
system/container manager it will be mounted with its *default* subvolume. The
|
||||
|
@ -161,8 +171,8 @@ subvolume set-default".
|
|||
|
||||
If two Linux-based operating systems are installed on the same disk, the scheme
|
||||
above suggests that they may share the swap, `/home/`, `/srv/`, `/var/tmp/`,
|
||||
ESP, XBOOTLDR. However, they should each have their own root and `/var/`
|
||||
partition.
|
||||
ESP, XBOOTLDR. However, they should each have their own root, `/usr/` and
|
||||
`/var/` partition.
|
||||
|
||||
## Frequently Asked Questions
|
||||
|
||||
|
|
|
@ -197,6 +197,76 @@
|
|||
<entry><constant>root-ia64-verity</constant></entry>
|
||||
<entry>Verity data for the ia64 root file system partition</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><constant>usr</constant></entry>
|
||||
<entry><filename>/usr/</filename> file system partition type appropriate for the local architecture (an alias for an architecture <filename>/usr/</filename> file system partition type listed below, e.g. <constant>usr-x86-64</constant>)</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><constant>usr-verity</constant></entry>
|
||||
<entry>Verity data for the <filename>/usr/</filename> file system partition for the local architecture</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><constant>usr-secondary</constant></entry>
|
||||
<entry><filename>/usr/</filename> file system partition of the secondary architecture of the local architecture (usually the matching 32bit architecture for the local 64bit architecture)</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><constant>usr-secondary-verity</constant></entry>
|
||||
<entry>Verity data for the <filename>/usr/</filename> file system partition of the secondary architecture</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><constant>usr-x86</constant></entry>
|
||||
<entry><filename>/usr/</filename> file system partition for the x86 (32bit, aka i386) architecture</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><constant>usr-x86-verity</constant></entry>
|
||||
<entry>Verity data for the x86 (32bit) <filename>/usr/</filename> file system partition</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><constant>usr-x86-64</constant></entry>
|
||||
<entry><filename>/usr/</filename> file system partition for the x86_64 (64bit, aka amd64) architecture</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><constant>usr-x86-64-verity</constant></entry>
|
||||
<entry>Verity data for the x86_64 (64bit) <filename>/usr/</filename> file system partition</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><constant>usr-arm</constant></entry>
|
||||
<entry><filename>/usr/</filename> file system partition for the ARM (32bit) architecture</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><constant>usr-arm-verity</constant></entry>
|
||||
<entry>Verity data for the ARM (32bit) <filename>/usr/</filename> file system partition</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><constant>usr-arm64</constant></entry>
|
||||
<entry><filename>/usr/</filename> file system partition for the ARM (64bit, aka aarch64) architecture</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><constant>usr-arm64-verity</constant></entry>
|
||||
<entry>Verity data for the ARM (64bit, aka aarch64) <filename>/usr/</filename> file system partition</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><constant>usr-ia64</constant></entry>
|
||||
<entry><filename>/usr/</filename> file system partition for the ia64 architecture</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><constant>usr-ia64-verity</constant></entry>
|
||||
<entry>Verity data for the ia64 <filename>/usr/</filename> file system partition</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
|
|
@ -74,6 +74,15 @@
|
|||
<option>--image=</option> switch, and be used as root file system for system service using the
|
||||
<varname>RootImage=</varname> unit file setting, see
|
||||
<citerefentry><refentrytitle>system.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
||||
|
||||
<para>Note that the partition table shown when invoked without command switch (as listed below) does not
|
||||
necessarily show all partitions included in the image, but just the partitions that are understood and
|
||||
considered part of an OS disk image. Specifically, partitions of unknown types are ignored, as well as
|
||||
duplicate partitions (i.e. more than one per partition type), as are root and <filename>/usr/</filename>
|
||||
partitions of architectures not compatible with the local system. In other words: this tool will display
|
||||
what it operates with when mounting the image. To display the complete list of partitions use a tool such
|
||||
as <citerefentry
|
||||
project='man-pages'><refentrytitle>fdisk</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
@ -246,7 +255,8 @@
|
|||
<citerefentry><refentrytitle>system-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>system.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||
<ulink url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partitions Specification</ulink>,
|
||||
<citerefentry project='man-pages'><refentrytitle>umount</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
<citerefentry project='man-pages'><refentrytitle>umount</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry project='man-pages'><refentrytitle>fdisk</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
|
|
@ -396,7 +396,15 @@
|
|||
is not supported by the underlying file system), but a file with the <filename>.roothash</filename> suffix is
|
||||
found next to the image file, bearing otherwise the same name (except if the image has the
|
||||
<filename>.raw</filename> suffix, in which case the root hash file must not have it in its name), the root hash
|
||||
is read from it and automatically used, also as formatted hexadecimal characters.</para></listitem>
|
||||
is read from it and automatically used, also as formatted hexadecimal characters.</para>
|
||||
|
||||
<para>Note that this configures the root hash for the root file system. Disk images may also contain
|
||||
separate file systems for the <filename>/usr/</filename> hierarchy, which may be Verity protected as
|
||||
well. The root hash for this protection may be configured via the
|
||||
<literal>user.verity.usrhash</literal> extended file attribute or via a <filename>.usrhash</filename>
|
||||
file adjacent to the disk image, following the same format and logic as for the root hash for the
|
||||
root file system described here. Note that there's currently no switch to configure the root hash for
|
||||
the <filename>/usr/</filename> from the command line.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -408,7 +416,12 @@
|
|||
string is valid and done by a public key present in the kernel keyring. If this option is not specified, but a
|
||||
file with the <filename>.roothash.p7s</filename> suffix is found next to the image file, bearing otherwise the
|
||||
same name (except if the image has the <filename>.raw</filename> suffix, in which case the signature file must
|
||||
not have it in its name), the signature is read from it and automatically used.</para></listitem>
|
||||
not have it in its name), the signature is read from it and automatically used.</para>
|
||||
|
||||
<para>The root hash for the <filename>/usr/</filename> file system included in a disk image may be
|
||||
configured via a <filename>.usrhash.p7s</filename> file adjacent to the disk image. There's currently
|
||||
no switch to configure the signature of the root hash of the <filename>/usr/</filename> file system
|
||||
from the command line.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
|
|
@ -193,6 +193,9 @@
|
|||
<row>
|
||||
<entry>var</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>usr</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
@ -216,6 +219,12 @@
|
|||
<filename>.raw</filename> suffix, in which case the root hash file must not have it in its name), the root hash
|
||||
is read from it and automatically used, also as formatted hexadecimal characters.</para>
|
||||
|
||||
<para>If the disk image contains a separate <filename>/usr/</filename> partition it may also be
|
||||
Verity protected, in which case the root hash may configured via an extended attribute
|
||||
<literal>user.verity.usrhash</literal> or a <filename>.usrhash</filename> file adjacent to the disk
|
||||
image. There's currently no option to configure the root hash for the <filename>/usr/</filename> file
|
||||
system via the unit file directly.</para>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -230,6 +239,12 @@
|
|||
the same name (except if the image has the <filename>.raw</filename> suffix, in which case the signature file
|
||||
must not have it in its name), the signature is read from it and automatically used.</para>
|
||||
|
||||
<para>If the disk image contains a separate <filename>/usr/</filename> partition it may also be
|
||||
Verity protected, in which case the signature for the root hash may configured via a
|
||||
<filename>.usrhash.p7s</filename> file adjacent to the disk image. There's currently no option to
|
||||
configure the root hash signature for the <filename>/usr/</filename> via the unit file
|
||||
directly.</para>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
|
|
@ -942,7 +942,7 @@ static int mount_images(const MountEntry *m) {
|
|||
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
|
||||
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
|
||||
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
|
||||
_cleanup_(verity_settings_done) VeritySettings verity = {};
|
||||
_cleanup_(verity_settings_done) VeritySettings verity = VERITY_SETTINGS_DEFAULT;
|
||||
DissectImageFlags dissect_image_flags;
|
||||
int r;
|
||||
|
||||
|
@ -1417,6 +1417,7 @@ static int verity_settings_prepare(
|
|||
|
||||
free_and_replace(verity->root_hash, d);
|
||||
verity->root_hash_size = root_hash_size;
|
||||
verity->designator = PARTITION_ROOT;
|
||||
}
|
||||
|
||||
if (root_hash_sig) {
|
||||
|
@ -1428,6 +1429,7 @@ static int verity_settings_prepare(
|
|||
|
||||
free_and_replace(verity->root_hash_sig, d);
|
||||
verity->root_hash_sig_size = root_hash_sig_size;
|
||||
verity->designator = PARTITION_ROOT;
|
||||
}
|
||||
|
||||
if (verity_data_path) {
|
||||
|
@ -1480,7 +1482,7 @@ int setup_namespace(
|
|||
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
|
||||
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
|
||||
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
|
||||
_cleanup_(verity_settings_done) VeritySettings verity = {};
|
||||
_cleanup_(verity_settings_done) VeritySettings verity = VERITY_SETTINGS_DEFAULT;
|
||||
MountEntry *m = NULL, *mounts = NULL;
|
||||
bool require_prefix = false;
|
||||
const char *root;
|
||||
|
|
|
@ -44,7 +44,7 @@ static const char *arg_path = NULL;
|
|||
static const char *arg_source = NULL;
|
||||
static const char *arg_target = NULL;
|
||||
static DissectImageFlags arg_flags = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK;
|
||||
static VeritySettings arg_verity_settings = {};
|
||||
static VeritySettings arg_verity_settings = VERITY_SETTINGS_DEFAULT;
|
||||
static bool arg_json = false;
|
||||
static JsonFormatFlags arg_json_format_flags = 0;
|
||||
|
||||
|
|
|
@ -201,7 +201,7 @@ static bool arg_notify_ready = false;
|
|||
static bool arg_use_cgns = true;
|
||||
static unsigned long arg_clone_ns_flags = CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS;
|
||||
static MountSettingsMask arg_mount_settings = MOUNT_APPLY_APIVFS_RO|MOUNT_APPLY_TMPFS_TMP;
|
||||
static VeritySettings arg_verity_settings = {};
|
||||
static VeritySettings arg_verity_settings = VERITY_SETTINGS_DEFAULT;
|
||||
static char **arg_syscall_allow_list = NULL;
|
||||
static char **arg_syscall_deny_list = NULL;
|
||||
#if HAVE_SECCOMP
|
||||
|
|
|
@ -310,7 +310,8 @@ int dissect_image(
|
|||
DissectedImage **ret) {
|
||||
|
||||
#if HAVE_BLKID
|
||||
sd_id128_t root_uuid = SD_ID128_NULL, verity_uuid = SD_ID128_NULL;
|
||||
sd_id128_t root_uuid = SD_ID128_NULL, root_verity_uuid = SD_ID128_NULL,
|
||||
usr_uuid = SD_ID128_NULL, usr_verity_uuid = SD_ID128_NULL;
|
||||
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
|
||||
bool is_gpt, is_mbr, generic_rw, multiple_generic = false;
|
||||
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
|
||||
|
@ -335,20 +336,32 @@ int dissect_image(
|
|||
* Returns -EADDRNOTAVAIL if a root hash was specified but no matching root/verity partitions found. */
|
||||
|
||||
if (verity && verity->root_hash) {
|
||||
/* If a root hash is supplied, then we use the root partition that has a UUID that match the first
|
||||
* 128bit of the root hash. And we use the verity partition that has a UUID that match the final
|
||||
* 128bit. */
|
||||
sd_id128_t fsuuid, vuuid;
|
||||
|
||||
/* If a root hash is supplied, then we use the root partition that has a UUID that match the
|
||||
* first 128bit of the root hash. And we use the verity partition that has a UUID that match
|
||||
* the final 128bit. */
|
||||
|
||||
if (verity->root_hash_size < sizeof(sd_id128_t))
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(&root_uuid, verity->root_hash, sizeof(sd_id128_t));
|
||||
memcpy(&verity_uuid, (const uint8_t*) verity->root_hash + verity->root_hash_size - sizeof(sd_id128_t), sizeof(sd_id128_t));
|
||||
memcpy(&fsuuid, verity->root_hash, sizeof(sd_id128_t));
|
||||
memcpy(&vuuid, (const uint8_t*) verity->root_hash + verity->root_hash_size - sizeof(sd_id128_t), sizeof(sd_id128_t));
|
||||
|
||||
if (sd_id128_is_null(root_uuid))
|
||||
if (sd_id128_is_null(fsuuid))
|
||||
return -EINVAL;
|
||||
if (sd_id128_is_null(verity_uuid))
|
||||
if (sd_id128_is_null(vuuid))
|
||||
return -EINVAL;
|
||||
|
||||
/* If the verity data declares it's for the /usr partition, then search for that, in all
|
||||
* other cases assume it's for the root partition. */
|
||||
if (verity->designator == PARTITION_USR) {
|
||||
usr_uuid = fsuuid;
|
||||
usr_verity_uuid = vuuid;
|
||||
} else {
|
||||
root_uuid = fsuuid;
|
||||
root_verity_uuid = vuuid;
|
||||
}
|
||||
}
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
|
@ -395,6 +408,8 @@ int dissect_image(
|
|||
(flags & DISSECT_IMAGE_NO_PARTITION_TABLE)) {
|
||||
const char *usage = NULL;
|
||||
|
||||
/* If flags permit this, also allow using non-partitioned single-filesystem images */
|
||||
|
||||
(void) blkid_probe_lookup_value(b, "USAGE", &usage, NULL);
|
||||
if (STRPTR_IN_SET(usage, "filesystem", "crypto")) {
|
||||
_cleanup_free_ char *t = NULL, *n = NULL, *o = NULL;
|
||||
|
@ -414,7 +429,7 @@ int dissect_image(
|
|||
return r;
|
||||
|
||||
m->single_file_system = true;
|
||||
m->verity = verity && verity->root_hash && verity->data_path;
|
||||
m->verity = verity && verity->root_hash && verity->data_path && (verity->designator < 0 || verity->designator == PARTITION_ROOT);
|
||||
m->can_verity = verity && verity->data_path;
|
||||
|
||||
options = mount_options_from_designator(mount_options, PARTITION_ROOT);
|
||||
|
@ -528,6 +543,7 @@ int dissect_image(
|
|||
|
||||
designator = PARTITION_HOME;
|
||||
rw = !(pflags & GPT_FLAG_READ_ONLY);
|
||||
|
||||
} else if (sd_id128_equal(type_id, GPT_SRV)) {
|
||||
|
||||
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
|
||||
|
@ -537,11 +553,13 @@ int dissect_image(
|
|||
|
||||
designator = PARTITION_SRV;
|
||||
rw = !(pflags & GPT_FLAG_READ_ONLY);
|
||||
|
||||
} else if (sd_id128_equal(type_id, GPT_ESP)) {
|
||||
|
||||
/* Note that we don't check the GPT_FLAG_NO_AUTO flag for the ESP, as it is not defined
|
||||
* there. We instead check the GPT_FLAG_NO_BLOCK_IO_PROTOCOL, as recommended by the
|
||||
* UEFI spec (See "12.3.3 Number and Location of System Partitions"). */
|
||||
/* Note that we don't check the GPT_FLAG_NO_AUTO flag for the ESP, as it is
|
||||
* not defined there. We instead check the GPT_FLAG_NO_BLOCK_IO_PROTOCOL, as
|
||||
* recommended by the UEFI spec (See "12.3.3 Number and Location of System
|
||||
* Partitions"). */
|
||||
|
||||
if (pflags & GPT_FLAG_NO_BLOCK_IO_PROTOCOL)
|
||||
continue;
|
||||
|
@ -574,6 +592,7 @@ int dissect_image(
|
|||
designator = PARTITION_ROOT;
|
||||
architecture = native_architecture();
|
||||
rw = !(pflags & GPT_FLAG_READ_ONLY);
|
||||
|
||||
} else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE_VERITY)) {
|
||||
|
||||
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
|
||||
|
@ -584,7 +603,7 @@ int dissect_image(
|
|||
m->can_verity = true;
|
||||
|
||||
/* Ignore verity unless a root hash is specified */
|
||||
if (sd_id128_is_null(verity_uuid) || !sd_id128_equal(verity_uuid, id))
|
||||
if (sd_id128_is_null(root_verity_uuid) || !sd_id128_equal(root_verity_uuid, id))
|
||||
continue;
|
||||
|
||||
designator = PARTITION_ROOT_VERITY;
|
||||
|
@ -608,6 +627,7 @@ int dissect_image(
|
|||
designator = PARTITION_ROOT_SECONDARY;
|
||||
architecture = SECONDARY_ARCHITECTURE;
|
||||
rw = !(pflags & GPT_FLAG_READ_ONLY);
|
||||
|
||||
} else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY_VERITY)) {
|
||||
|
||||
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
|
||||
|
@ -618,7 +638,7 @@ int dissect_image(
|
|||
m->can_verity = true;
|
||||
|
||||
/* Ignore verity unless root has is specified */
|
||||
if (sd_id128_is_null(verity_uuid) || !sd_id128_equal(verity_uuid, id))
|
||||
if (sd_id128_is_null(root_verity_uuid) || !sd_id128_equal(root_verity_uuid, id))
|
||||
continue;
|
||||
|
||||
designator = PARTITION_ROOT_SECONDARY_VERITY;
|
||||
|
@ -626,6 +646,76 @@ int dissect_image(
|
|||
architecture = SECONDARY_ARCHITECTURE;
|
||||
rw = false;
|
||||
}
|
||||
#endif
|
||||
#ifdef GPT_USR_NATIVE
|
||||
else if (sd_id128_equal(type_id, GPT_USR_NATIVE)) {
|
||||
|
||||
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
|
||||
|
||||
if (pflags & GPT_FLAG_NO_AUTO)
|
||||
continue;
|
||||
|
||||
/* If a usr ID is specified, ignore everything but the usr id */
|
||||
if (!sd_id128_is_null(usr_uuid) && !sd_id128_equal(usr_uuid, id))
|
||||
continue;
|
||||
|
||||
designator = PARTITION_USR;
|
||||
architecture = native_architecture();
|
||||
rw = !(pflags & GPT_FLAG_READ_ONLY);
|
||||
|
||||
} else if (sd_id128_equal(type_id, GPT_USR_NATIVE_VERITY)) {
|
||||
|
||||
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
|
||||
|
||||
if (pflags & GPT_FLAG_NO_AUTO)
|
||||
continue;
|
||||
|
||||
m->can_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))
|
||||
continue;
|
||||
|
||||
designator = PARTITION_USR_VERITY;
|
||||
fstype = "DM_verity_hash";
|
||||
architecture = native_architecture();
|
||||
rw = false;
|
||||
}
|
||||
#endif
|
||||
#ifdef GPT_USR_SECONDARY
|
||||
else if (sd_id128_equal(type_id, GPT_USR_SECONDARY)) {
|
||||
|
||||
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
|
||||
|
||||
if (pflags & GPT_FLAG_NO_AUTO)
|
||||
continue;
|
||||
|
||||
/* If a usr ID is specified, ignore everything but the usr id */
|
||||
if (!sd_id128_is_null(usr_uuid) && !sd_id128_equal(usr_uuid, id))
|
||||
continue;
|
||||
|
||||
designator = PARTITION_USR_SECONDARY;
|
||||
architecture = SECONDARY_ARCHITECTURE;
|
||||
rw = !(pflags & GPT_FLAG_READ_ONLY);
|
||||
|
||||
} else if (sd_id128_equal(type_id, GPT_USR_SECONDARY_VERITY)) {
|
||||
|
||||
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
|
||||
|
||||
if (pflags & GPT_FLAG_NO_AUTO)
|
||||
continue;
|
||||
|
||||
m->can_verity = true;
|
||||
|
||||
/* Ignore verity unless usr has is specified */
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
else if (sd_id128_equal(type_id, GPT_SWAP)) {
|
||||
|
||||
|
@ -636,6 +726,7 @@ int dissect_image(
|
|||
|
||||
designator = PARTITION_SWAP;
|
||||
fstype = "swap";
|
||||
|
||||
} else if (sd_id128_equal(type_id, GPT_LINUX_GENERIC)) {
|
||||
|
||||
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
|
||||
|
@ -798,6 +889,8 @@ 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_USR_SECONDARY].found = false;
|
||||
m->partitions[PARTITION_USR_SECONDARY_VERITY].found = false;
|
||||
} else {
|
||||
/* No root partition found? Then let's see if ther's one for the secondary architecture. And if not
|
||||
* either, then check if there's a single generic one, and use that. */
|
||||
|
@ -805,13 +898,22 @@ int dissect_image(
|
|||
if (m->partitions[PARTITION_ROOT_VERITY].found)
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
/* We didn't find a primary architecture root, but we found a primary architecture /usr? Refuse that for now. */
|
||||
if (m->partitions[PARTITION_USR].found || m->partitions[PARTITION_USR_VERITY].found)
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
if (m->partitions[PARTITION_ROOT_SECONDARY].found) {
|
||||
/* Upgrade secondary arch to first */
|
||||
m->partitions[PARTITION_ROOT] = m->partitions[PARTITION_ROOT_SECONDARY];
|
||||
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_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]);
|
||||
|
||||
} else if (flags & DISSECT_IMAGE_REQUIRE_ROOT) {
|
||||
_cleanup_free_ char *o = NULL;
|
||||
const char *options = NULL;
|
||||
|
@ -849,14 +951,31 @@ int dissect_image(
|
|||
}
|
||||
}
|
||||
|
||||
/* Refuse if we found a verity partition for /usr but no matching file system partition */
|
||||
if (!m->partitions[PARTITION_USR].found && m->partitions[PARTITION_USR_VERITY].found)
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
/* Combinations of verity /usr with verity-less root is OK, but the reverse is not */
|
||||
if (m->partitions[PARTITION_ROOT_VERITY].found && !m->partitions[PARTITION_USR_VERITY].found)
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
if (verity && verity->root_hash) {
|
||||
if (!m->partitions[PARTITION_ROOT_VERITY].found || !m->partitions[PARTITION_ROOT].found)
|
||||
return -EADDRNOTAVAIL;
|
||||
if (verity->designator < 0 || verity->designator == PARTITION_ROOT) {
|
||||
if (!m->partitions[PARTITION_ROOT_VERITY].found || !m->partitions[PARTITION_ROOT].found)
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
/* If we found a verity setup, then the root partition is necessarily read-only. */
|
||||
m->partitions[PARTITION_ROOT].rw = false;
|
||||
/* If we found a verity setup, then the root partition is necessarily read-only. */
|
||||
m->partitions[PARTITION_ROOT].rw = false;
|
||||
m->verity = true;
|
||||
}
|
||||
|
||||
m->verity = true;
|
||||
if (verity->designator == PARTITION_USR) {
|
||||
if (!m->partitions[PARTITION_USR_VERITY].found || !m->partitions[PARTITION_USR].found)
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
m->partitions[PARTITION_USR].rw = false;
|
||||
m->verity = true;
|
||||
}
|
||||
}
|
||||
|
||||
blkid_free_probe(b);
|
||||
|
@ -883,7 +1002,6 @@ int dissect_image(
|
|||
}
|
||||
|
||||
*ret = TAKE_PTR(m);
|
||||
|
||||
return 0;
|
||||
#else
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -1089,6 +1207,17 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift,
|
|||
r = mount_partition(m->partitions + PARTITION_ROOT, where, NULL, uid_shift, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Mask DISSECT_IMAGE_MKDIR for all subdirs: the idea is that only the top-level mount point is
|
||||
* created if needed, but the image itself not modified. */
|
||||
flags &= ~DISSECT_IMAGE_MKDIR;
|
||||
|
||||
if ((flags & DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY) == 0) {
|
||||
/* For us mounting root always means mounting /usr as well */
|
||||
r = mount_partition(m->partitions + PARTITION_USR, where, "/usr", uid_shift, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (flags & DISSECT_IMAGE_VALIDATE_OS) {
|
||||
r = path_is_os_tree(where);
|
||||
|
@ -1102,10 +1231,6 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift,
|
|||
if (flags & DISSECT_IMAGE_MOUNT_ROOT_ONLY)
|
||||
return 0;
|
||||
|
||||
/* Mask DISSECT_IMAGE_MKDIR for all subdirs: the idea is that only the top-level mount point is
|
||||
* created if needed, but the image itself not modified. */
|
||||
flags &= ~DISSECT_IMAGE_MKDIR;
|
||||
|
||||
r = mount_partition(m->partitions + PARTITION_HOME, where, "/home", uid_shift, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -1389,6 +1514,7 @@ static inline void dm_deferred_remove_clean(char *name) {
|
|||
DEFINE_TRIVIAL_CLEANUP_FUNC(char *, dm_deferred_remove_clean);
|
||||
|
||||
static int verity_partition(
|
||||
PartitionDesignator designator,
|
||||
DissectedPartition *m,
|
||||
DissectedPartition *v,
|
||||
const VeritySettings *verity,
|
||||
|
@ -1405,6 +1531,9 @@ static int verity_partition(
|
|||
|
||||
if (!verity || !verity->root_hash)
|
||||
return 0;
|
||||
if (!((verity->designator < 0 && designator == PARTITION_ROOT) ||
|
||||
(verity->designator == designator)))
|
||||
return 0;
|
||||
|
||||
if (!m->found || !m->node || !m->fstype)
|
||||
return 0;
|
||||
|
@ -1426,8 +1555,8 @@ static int verity_partition(
|
|||
|
||||
root_hash_encoded = hexmem(verity->root_hash, verity->root_hash_size);
|
||||
if (!root_hash_encoded)
|
||||
|
||||
return -ENOMEM;
|
||||
|
||||
r = make_dm_name_and_node(root_hash_encoded, "-verity", &name, &node);
|
||||
} else
|
||||
r = make_dm_name_and_node(m->node, "-verity", &name, &node);
|
||||
|
@ -1482,7 +1611,7 @@ static int verity_partition(
|
|||
* Improvements in libcrypsetup can ensure this never happens:
|
||||
* https://gitlab.com/cryptsetup/cryptsetup/-/merge_requests/96 */
|
||||
if (r == -EINVAL && FLAGS_SET(flags, DISSECT_IMAGE_VERITY_SHARE))
|
||||
return verity_partition(m, v, verity, flags & ~DISSECT_IMAGE_VERITY_SHARE, d);
|
||||
return verity_partition(designator, m, v, verity, flags & ~DISSECT_IMAGE_VERITY_SHARE, d);
|
||||
if (!IN_SET(r,
|
||||
0, /* Success */
|
||||
-EEXIST, /* Volume is already open and ready to be used */
|
||||
|
@ -1508,7 +1637,7 @@ static int verity_partition(
|
|||
r = verity_can_reuse(verity, name, &existing_cd);
|
||||
/* Same as above, -EINVAL can randomly happen when it actually means -EEXIST */
|
||||
if (r == -EINVAL && FLAGS_SET(flags, DISSECT_IMAGE_VERITY_SHARE))
|
||||
return verity_partition(m, v, verity, flags & ~DISSECT_IMAGE_VERITY_SHARE, d);
|
||||
return verity_partition(designator, m, v, verity, flags & ~DISSECT_IMAGE_VERITY_SHARE, d);
|
||||
if (!IN_SET(r, 0, -ENODEV, -ENOENT, -EBUSY))
|
||||
return log_debug_errno(r, "Checking whether existing verity device %s can be reused failed: %m", node);
|
||||
if (r == 0) {
|
||||
|
@ -1536,7 +1665,7 @@ static int verity_partition(
|
|||
/* An existing verity device was reported by libcryptsetup/libdevmapper, but we can't use it at this time.
|
||||
* Fall back to activating it with a unique device name. */
|
||||
if (r != 0 && FLAGS_SET(flags, DISSECT_IMAGE_VERITY_SHARE))
|
||||
return verity_partition(m, v, verity, flags & ~DISSECT_IMAGE_VERITY_SHARE, d);
|
||||
return verity_partition(designator, m, v, verity, flags & ~DISSECT_IMAGE_VERITY_SHARE, d);
|
||||
|
||||
/* Everything looks good and we'll be able to mount the device, so deferred remove will be re-enabled at that point. */
|
||||
restore_deferred_remove = mfree(restore_deferred_remove);
|
||||
|
@ -1601,7 +1730,7 @@ int dissected_image_decrypt(
|
|||
|
||||
k = PARTITION_VERITY_OF(i);
|
||||
if (k >= 0) {
|
||||
r = verity_partition(p, m->partitions + k, verity, flags | DISSECT_IMAGE_VERITY_SHARE, d);
|
||||
r = verity_partition(i, p, m->partitions + k, verity, flags | DISSECT_IMAGE_VERITY_SHARE, d);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
@ -1727,39 +1856,84 @@ int verity_settings_load(
|
|||
_cleanup_free_ void *root_hash = NULL, *root_hash_sig = NULL;
|
||||
size_t root_hash_size = 0, root_hash_sig_size = 0;
|
||||
_cleanup_free_ char *verity_data_path = NULL;
|
||||
PartitionDesignator designator;
|
||||
int r;
|
||||
|
||||
assert(verity);
|
||||
assert(image);
|
||||
assert(verity->designator < 0 || IN_SET(verity->designator, PARTITION_ROOT, PARTITION_USR));
|
||||
|
||||
/* If we are asked to load the root hash for a device node, exit early */
|
||||
if (is_device_path(image))
|
||||
return 0;
|
||||
|
||||
designator = verity->designator;
|
||||
|
||||
/* We only fill in what isn't already filled in */
|
||||
|
||||
if (!verity->root_hash) {
|
||||
_cleanup_free_ char *text = NULL;
|
||||
|
||||
if (root_hash_path) {
|
||||
/* If explicitly specified it takes precedence */
|
||||
r = read_one_line_file(root_hash_path, &text);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (designator < 0)
|
||||
designator = PARTITION_ROOT;
|
||||
} else {
|
||||
r = getxattr_malloc(image, "user.verity.roothash", &text, true);
|
||||
if (r < 0) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
/* Otherwise look for xattr and separate file, and first for the data for root and if
|
||||
* that doesn't exist for /usr */
|
||||
|
||||
if (!IN_SET(r, -ENODATA, -ENOENT) && !ERRNO_IS_NOT_SUPPORTED(r))
|
||||
return r;
|
||||
if (designator < 0 || designator == PARTITION_ROOT) {
|
||||
r = getxattr_malloc(image, "user.verity.roothash", &text, true);
|
||||
if (r < 0) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
p = build_auxiliary_path(image, ".roothash");
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
if (!IN_SET(r, -ENODATA, -ENOENT) && !ERRNO_IS_NOT_SUPPORTED(r))
|
||||
return r;
|
||||
|
||||
r = read_one_line_file(p, &text);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
p = build_auxiliary_path(image, ".roothash");
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
r = read_one_line_file(p, &text);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (text)
|
||||
designator = PARTITION_ROOT;
|
||||
}
|
||||
|
||||
if (!text && (designator < 0 || designator == PARTITION_USR)) {
|
||||
/* So in the "roothash" xattr/file name above the "root" of course primarily
|
||||
* refers to the root of the Verity Merkle tree. But coincidentally it also
|
||||
* is the hash for the *root* file system, i.e. the "root" neatly refers to
|
||||
* two distinct concepts called "root". Taking benefit of this happy
|
||||
* coincidence we call the file with the root hash for the /usr/ file system
|
||||
* `usrhash`, because `usrroothash` or `rootusrhash` would just be too
|
||||
* confusing. We thus drop the reference to the root of the Merkle tree, and
|
||||
* just indicate which file system it's about. */
|
||||
r = getxattr_malloc(image, "user.verity.usrhash", &text, true);
|
||||
if (r < 0) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
if (!IN_SET(r, -ENODATA, -ENOENT) && !ERRNO_IS_NOT_SUPPORTED(r))
|
||||
return r;
|
||||
|
||||
p = build_auxiliary_path(image, ".usrhash");
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
r = read_one_line_file(p, &text);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (text)
|
||||
designator = PARTITION_USR;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1772,24 +1946,47 @@ int verity_settings_load(
|
|||
}
|
||||
}
|
||||
|
||||
if (!verity->root_hash_sig) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
if (verity->root_hash && !verity->root_hash_sig) {
|
||||
if (root_hash_sig_path) {
|
||||
r = read_full_file_full(AT_FDCWD, root_hash_sig_path, 0, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
|
||||
if (!root_hash_sig_path) {
|
||||
/* Follow naming convention recommended by the relevant RFC:
|
||||
* https://tools.ietf.org/html/rfc5751#section-3.2.1 */
|
||||
p = build_auxiliary_path(image, ".roothash.p7s");
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
if (designator < 0)
|
||||
designator = PARTITION_ROOT;
|
||||
} else {
|
||||
if (designator < 0 || designator == PARTITION_ROOT) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
root_hash_sig_path = p;
|
||||
/* Follow naming convention recommended by the relevant RFC:
|
||||
* https://tools.ietf.org/html/rfc5751#section-3.2.1 */
|
||||
p = build_auxiliary_path(image, ".roothash.p7s");
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
r = read_full_file_full(AT_FDCWD, root_hash_sig_path, 0, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
if (r >= 0)
|
||||
designator = PARTITION_ROOT;
|
||||
}
|
||||
|
||||
if (!root_hash_sig && (designator < 0 || designator == PARTITION_USR)) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
p = build_auxiliary_path(image, ".usrhash.p7s");
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
r = read_full_file_full(AT_FDCWD, root_hash_sig_path, 0, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
if (r >= 0)
|
||||
designator = PARTITION_USR;
|
||||
}
|
||||
}
|
||||
|
||||
r = read_full_file_full(AT_FDCWD, root_hash_sig_path, 0, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||
if (r < 0) {
|
||||
if (r != -ENOENT)
|
||||
return r;
|
||||
} else if (root_hash_sig_size == 0) /* refuse empty size signatures */
|
||||
if (root_hash_sig && root_hash_sig_size == 0) /* refuse empty size signatures */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -1820,6 +2017,9 @@ int verity_settings_load(
|
|||
if (verity_data_path)
|
||||
verity->data_path = TAKE_PTR(verity_data_path);
|
||||
|
||||
if (verity->designator < 0)
|
||||
verity->designator = designator;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -2018,7 +2218,6 @@ int dissect_image_and_warn(
|
|||
}
|
||||
|
||||
r = dissect_image(fd, verity, mount_options, flags, ret);
|
||||
|
||||
switch (r) {
|
||||
|
||||
case -EOPNOTSUPP:
|
||||
|
@ -2161,6 +2360,8 @@ int mount_image_privately_interactively(
|
|||
static const char *const partition_designator_table[] = {
|
||||
[PARTITION_ROOT] = "root",
|
||||
[PARTITION_ROOT_SECONDARY] = "root-secondary",
|
||||
[PARTITION_USR] = "usr",
|
||||
[PARTITION_USR_SECONDARY] = "usr-secondary",
|
||||
[PARTITION_HOME] = "home",
|
||||
[PARTITION_SRV] = "srv",
|
||||
[PARTITION_ESP] = "esp",
|
||||
|
@ -2168,6 +2369,8 @@ static const char *const partition_designator_table[] = {
|
|||
[PARTITION_SWAP] = "swap",
|
||||
[PARTITION_ROOT_VERITY] = "root-verity",
|
||||
[PARTITION_ROOT_SECONDARY_VERITY] = "root-secondary-verity",
|
||||
[PARTITION_USR_VERITY] = "usr-verity",
|
||||
[PARTITION_USR_SECONDARY_VERITY] = "usr-secondary-verity",
|
||||
[PARTITION_TMP] = "tmp",
|
||||
[PARTITION_VAR] = "var",
|
||||
};
|
||||
|
|
|
@ -31,6 +31,8 @@ struct DissectedPartition {
|
|||
typedef enum PartitionDesignator {
|
||||
PARTITION_ROOT,
|
||||
PARTITION_ROOT_SECONDARY, /* Secondary architecture */
|
||||
PARTITION_USR,
|
||||
PARTITION_USR_SECONDARY,
|
||||
PARTITION_HOME,
|
||||
PARTITION_SRV,
|
||||
PARTITION_ESP,
|
||||
|
@ -38,6 +40,8 @@ typedef enum PartitionDesignator {
|
|||
PARTITION_SWAP,
|
||||
PARTITION_ROOT_VERITY, /* verity data for the PARTITION_ROOT partition */
|
||||
PARTITION_ROOT_SECONDARY_VERITY, /* verity data for the PARTITION_ROOT_SECONDARY partition */
|
||||
PARTITION_USR_VERITY,
|
||||
PARTITION_USR_SECONDARY_VERITY,
|
||||
PARTITION_TMP,
|
||||
PARTITION_VAR,
|
||||
_PARTITION_DESIGNATOR_MAX,
|
||||
|
@ -45,11 +49,23 @@ typedef enum PartitionDesignator {
|
|||
} PartitionDesignator;
|
||||
|
||||
static inline PartitionDesignator PARTITION_VERITY_OF(PartitionDesignator p) {
|
||||
if (p == PARTITION_ROOT)
|
||||
switch (p) {
|
||||
|
||||
case PARTITION_ROOT:
|
||||
return PARTITION_ROOT_VERITY;
|
||||
if (p == PARTITION_ROOT_SECONDARY)
|
||||
|
||||
case PARTITION_ROOT_SECONDARY:
|
||||
return PARTITION_ROOT_SECONDARY_VERITY;
|
||||
return _PARTITION_DESIGNATOR_INVALID;
|
||||
|
||||
case PARTITION_USR:
|
||||
return PARTITION_USR_VERITY;
|
||||
|
||||
case PARTITION_USR_SECONDARY:
|
||||
return PARTITION_USR_SECONDARY_VERITY;
|
||||
|
||||
default:
|
||||
return _PARTITION_DESIGNATOR_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum DissectImageFlags {
|
||||
|
@ -61,9 +77,9 @@ typedef enum DissectImageFlags {
|
|||
DISSECT_IMAGE_DISCARD |
|
||||
DISSECT_IMAGE_DISCARD_ON_CRYPTO,
|
||||
DISSECT_IMAGE_GPT_ONLY = 1 << 4, /* Only recognize images with GPT partition tables */
|
||||
DISSECT_IMAGE_REQUIRE_ROOT = 1 << 5, /* Don't accept disks without root partition */
|
||||
DISSECT_IMAGE_MOUNT_ROOT_ONLY = 1 << 6, /* Mount only the root partition */
|
||||
DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY = 1 << 7, /* Mount only non-root partitions */
|
||||
DISSECT_IMAGE_REQUIRE_ROOT = 1 << 5, /* Don't accept disks without root partition (and if no partition table or only single generic partition, assume it's root) */
|
||||
DISSECT_IMAGE_MOUNT_ROOT_ONLY = 1 << 6, /* Mount only the root and /usr partitions */
|
||||
DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY = 1 << 7, /* Mount only the non-root and non-/usr partitions */
|
||||
DISSECT_IMAGE_VALIDATE_OS = 1 << 8, /* Refuse mounting images that aren't identifiable as OS images */
|
||||
DISSECT_IMAGE_NO_UDEV = 1 << 9, /* Don't wait for udev initializing things */
|
||||
DISSECT_IMAGE_RELAX_VAR_CHECK = 1 << 10, /* Don't insist that the UUID of /var is hashed from /etc/machine-id */
|
||||
|
@ -104,8 +120,15 @@ struct VeritySettings {
|
|||
|
||||
/* Path to the verity data file, if stored externally */
|
||||
char *data_path;
|
||||
|
||||
/* PARTITION_ROOT or PARTITION_USR, depending on what these Verity settings are for */
|
||||
PartitionDesignator designator;
|
||||
};
|
||||
|
||||
#define VERITY_SETTINGS_DEFAULT { \
|
||||
.designator = _PARTITION_DESIGNATOR_INVALID \
|
||||
}
|
||||
|
||||
MountOptions* mount_options_free_all(MountOptions *options);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(MountOptions*, mount_options_free_all);
|
||||
const char* mount_options_from_designator(const MountOptions *options, PartitionDesignator designator);
|
||||
|
|
|
@ -21,6 +21,24 @@ const GptPartitionType gpt_partition_type_table[] = {
|
|||
#ifdef GPT_ROOT_SECONDARY
|
||||
{ GPT_ROOT_SECONDARY, "root-secondary" },
|
||||
{ GPT_ROOT_SECONDARY_VERITY, "root-secondary-verity" },
|
||||
#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" },
|
||||
#ifdef GPT_USR_NATIVE
|
||||
{ GPT_USR_NATIVE, "usr" },
|
||||
{ GPT_USR_NATIVE_VERITY, "usr-verity" },
|
||||
#endif
|
||||
#ifdef GPT_USR_SECONDARY
|
||||
{ GPT_USR_SECONDARY, "usr-secondary" },
|
||||
{ GPT_USR_SECONDARY_VERITY, "usr-secondary-verity" },
|
||||
#endif
|
||||
{ GPT_ESP, "esp" },
|
||||
{ GPT_XBOOTLDR, "xbootldr" },
|
||||
|
|
|
@ -15,6 +15,11 @@
|
|||
#define GPT_ROOT_ARM SD_ID128_MAKE(69,da,d7,10,2c,e4,4e,3c,b1,6c,21,a1,d4,9a,be,d3)
|
||||
#define GPT_ROOT_ARM_64 SD_ID128_MAKE(b9,21,b0,45,1d,f0,41,c3,af,44,4c,6f,28,0d,3f,ae)
|
||||
#define GPT_ROOT_IA64 SD_ID128_MAKE(99,3d,8d,3d,f8,0e,42,25,85,5a,9d,af,8e,d7,ea,97)
|
||||
#define GPT_USR_X86 SD_ID128_MAKE(75,25,0d,76,8c,c6,45,8e,bd,66,bd,47,cc,81,a8,12)
|
||||
#define GPT_USR_X86_64 SD_ID128_MAKE(84,84,68,0c,95,21,48,c6,9c,11,b0,72,06,56,f6,9e)
|
||||
#define GPT_USR_ARM SD_ID128_MAKE(7d,03,59,a3,02,b3,4f,0a,86,5c,65,44,03,e7,06,25)
|
||||
#define GPT_USR_ARM_64 SD_ID128_MAKE(b0,e0,10,50,ee,5f,43,90,94,9a,91,01,b1,71,04,e9)
|
||||
#define GPT_USR_IA64 SD_ID128_MAKE(43,01,d2,a6,4e,3b,4b,2a,bb,94,9e,0b,2c,42,25,ea)
|
||||
#define GPT_ESP SD_ID128_MAKE(c1,2a,73,28,f8,1f,11,d2,ba,4b,00,a0,c9,3e,c9,3b)
|
||||
#define GPT_XBOOTLDR SD_ID128_MAKE(bc,13,c2,ff,59,e6,42,62,a3,52,b2,75,fd,6f,71,72)
|
||||
#define GPT_SWAP SD_ID128_MAKE(06,57,fd,6d,a4,ab,43,c4,84,e5,09,33,c8,4b,4f,4f)
|
||||
|
@ -25,27 +30,40 @@
|
|||
#define GPT_USER_HOME SD_ID128_MAKE(77,3f,91,ef,66,d4,49,b5,bd,83,d6,83,bf,40,ad,16)
|
||||
#define GPT_LINUX_GENERIC SD_ID128_MAKE(0f,c6,3d,af,84,83,47,72,8e,79,3d,69,d8,47,7d,e4)
|
||||
|
||||
/* Verity partitions for the root partitions above (we only define them for the root partitions, because only
|
||||
* they are are commonly read-only and hence suitable for verity). */
|
||||
/* Verity partitions for the root partitions above (we only define them for the root and /usr partitions,
|
||||
* because only they are are commonly read-only and hence suitable for verity). */
|
||||
#define GPT_ROOT_X86_VERITY SD_ID128_MAKE(d1,3c,5d,3b,b5,d1,42,2a,b2,9f,94,54,fd,c8,9d,76)
|
||||
#define GPT_ROOT_X86_64_VERITY SD_ID128_MAKE(2c,73,57,ed,eb,d2,46,d9,ae,c1,23,d4,37,ec,2b,f5)
|
||||
#define GPT_ROOT_ARM_VERITY SD_ID128_MAKE(73,86,cd,f2,20,3c,47,a9,a4,98,f2,ec,ce,45,a2,d6)
|
||||
#define GPT_ROOT_ARM_64_VERITY SD_ID128_MAKE(df,33,00,ce,d6,9f,4c,92,97,8c,9b,fb,0f,38,d8,20)
|
||||
#define GPT_ROOT_IA64_VERITY SD_ID128_MAKE(86,ed,10,d5,b6,07,45,bb,89,57,d3,50,f2,3d,05,71)
|
||||
#define GPT_USR_X86_VERITY SD_ID128_MAKE(8f,46,1b,0d,14,ee,4e,81,9a,a9,04,9b,6f,b9,7a,bd)
|
||||
#define GPT_USR_X86_64_VERITY SD_ID128_MAKE(77,ff,5f,63,e7,b6,46,33,ac,f4,15,65,b8,64,c0,e6)
|
||||
#define GPT_USR_ARM_VERITY SD_ID128_MAKE(c2,15,d7,51,7b,cd,46,49,be,90,66,27,49,0a,4c,05)
|
||||
#define GPT_USR_ARM_64_VERITY SD_ID128_MAKE(6e,11,a4,e7,fb,ca,4d,ed,b9,e9,e1,a5,12,bb,66,4e)
|
||||
#define GPT_USR_IA64_VERITY SD_ID128_MAKE(6a,49,1e,03,3b,e7,45,45,8e,38,83,32,0e,0e,a8,80)
|
||||
|
||||
#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_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
|
||||
#elif defined(__i386__)
|
||||
# define GPT_ROOT_NATIVE GPT_ROOT_X86
|
||||
# define GPT_ROOT_NATIVE_VERITY GPT_ROOT_X86_VERITY
|
||||
# define GPT_USR_NATIVE GPT_USR_X86
|
||||
# define GPT_USR_NATIVE_VERITY GPT_USR_X86_VERITY
|
||||
#endif
|
||||
|
||||
#if defined(__ia64__)
|
||||
# define GPT_ROOT_NATIVE GPT_ROOT_IA64
|
||||
# define GPT_ROOT_NATIVE_VERITY GPT_ROOT_IA64_VERITY
|
||||
# define GPT_USR_NATIVE GPT_USR_IA64
|
||||
# define GPT_USR_NATIVE_VERITY GPT_USR_IA64_VERITY
|
||||
#endif
|
||||
|
||||
#if defined(__aarch64__) && (__BYTE_ORDER != __BIG_ENDIAN)
|
||||
|
@ -53,18 +71,24 @@
|
|||
# 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_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
|
||||
#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_USR_NATIVE GPT_USR_ARM
|
||||
# define GPT_USR_NATIVE_VERITY GPT_USR_ARM_VERITY
|
||||
#endif
|
||||
|
||||
#define GPT_FLAG_REQUIRED_PARTITION (1ULL << 0)
|
||||
#define GPT_FLAG_NO_BLOCK_IO_PROTOCOL (1ULL << 1)
|
||||
#define GPT_FLAG_LEGACY_BIOS_BOOTABLE (1ULL << 2)
|
||||
|
||||
/* Flags we recognize on the root, swap, home and srv partitions when doing auto-discovery. These happen to
|
||||
* be identical to what Microsoft defines for its own Basic Data Partitions, but that's just because we saw
|
||||
* no point in defining any other values here. */
|
||||
/* Flags we recognize on the root, usr, xbootldr, swap, home, srv, var, tmp partitions when doing
|
||||
* auto-discovery. These happen to be identical to what Microsoft defines for its own Basic Data Partitions,
|
||||
* but that's just because we saw no point in defining any other values here. */
|
||||
#define GPT_FLAG_READ_ONLY (1ULL << 60)
|
||||
#define GPT_FLAG_NO_AUTO (1ULL << 63)
|
||||
|
||||
|
|
Loading…
Reference in New Issue