Systemd/src/shared/dissect-image.h

125 lines
6.4 KiB
C
Raw Normal View History

/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <stdbool.h>
#include "sd-id128.h"
#include "list.h"
#include "loop-util.h"
#include "macro.h"
typedef struct DissectedImage DissectedImage;
typedef struct DissectedPartition DissectedPartition;
typedef struct DecryptedImage DecryptedImage;
typedef struct MountOptions MountOptions;
struct DissectedPartition {
bool found:1;
bool rw:1;
int partno; /* -1 if there was no partition and the images contains a file system directly */
int architecture; /* Intended architecture: either native, secondary or unset (-1). */
sd_id128_t uuid; /* Partition entry UUID as reported by the GPT */
char *fstype;
char *node;
char *decrypted_node;
char *decrypted_fstype;
char *mount_options;
};
enum {
PARTITION_ROOT,
PARTITION_ROOT_SECONDARY, /* Secondary architecture */
PARTITION_HOME,
PARTITION_SRV,
PARTITION_ESP,
PARTITION_XBOOTLDR,
PARTITION_SWAP,
PARTITION_ROOT_VERITY, /* verity data for the PARTITION_ROOT partition */
PARTITION_ROOT_SECONDARY_VERITY, /* verity data for the PARTITION_ROOT_SECONDARY partition */
dissect: introduce new recognizable partition types for /var and /var/tmp This has been requested many times before. Let's add it finally. GPT auto-discovery for /var is a bit more complex than for other partition types: the other partitions can to some degree be shared between multiple OS installations on the same disk (think: swap, /home, /srv). However, /var is inherently something bound to an installation, i.e. specific to its identity, or actually *is* its identity, and hence something that cannot be shared. To deal with this this new code is particularly careful when it comes to /var: it will not mount things blindly, but insist that the UUID of the partition matches a hashed version of the machine-id of the installation, so that each installation has a very specific /var associated with it, and would never use any other. (We actually use HMAC-SHA256 on the GPT partition type for /var, keyed by the machine-id, since machine-id is something we want to keep somewhat private). Setting the right UUID for installations takes extra care. To make things a bit simpler to set up, we avoid this safety check for nspawn and RootImage= in unit files, under the assumption that such container and service images unlikely will have multiple installations on them. The check is hence only required when booting full machines, i.e. in in systemd-gpt-auto-generator. To help with putting together images for full machines, PR #14368 introduces a repartition tool that can automatically fill in correctly calculated UUIDs on first boot if images have the var partition UUID initialized to all zeroes. With that in place systems can be put together in a way that on first boot the machine ID is determined and the partition table automatically adjusted to have the /var partition with the right UUID.
2019-12-18 12:22:40 +01:00
PARTITION_TMP,
PARTITION_VAR,
_PARTITION_DESIGNATOR_MAX,
_PARTITION_DESIGNATOR_INVALID = -1
};
static inline int PARTITION_VERITY_OF(int p) {
if (p == PARTITION_ROOT)
return PARTITION_ROOT_VERITY;
if (p == PARTITION_ROOT_SECONDARY)
return PARTITION_ROOT_SECONDARY_VERITY;
return _PARTITION_DESIGNATOR_INVALID;
}
typedef enum DissectImageFlags {
DISSECT_IMAGE_READ_ONLY = 1 << 0,
DISSECT_IMAGE_DISCARD_ON_LOOP = 1 << 1, /* Turn on "discard" if on a loop device and file system supports it */
DISSECT_IMAGE_DISCARD = 1 << 2, /* Turn on "discard" if file system supports it, on all block devices */
DISSECT_IMAGE_DISCARD_ON_CRYPTO = 1 << 3, /* Turn on "discard" also on crypto devices */
DISSECT_IMAGE_DISCARD_ANY = DISSECT_IMAGE_DISCARD_ON_LOOP |
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 */
2019-04-27 02:22:40 +02:00
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: introduce new recognizable partition types for /var and /var/tmp This has been requested many times before. Let's add it finally. GPT auto-discovery for /var is a bit more complex than for other partition types: the other partitions can to some degree be shared between multiple OS installations on the same disk (think: swap, /home, /srv). However, /var is inherently something bound to an installation, i.e. specific to its identity, or actually *is* its identity, and hence something that cannot be shared. To deal with this this new code is particularly careful when it comes to /var: it will not mount things blindly, but insist that the UUID of the partition matches a hashed version of the machine-id of the installation, so that each installation has a very specific /var associated with it, and would never use any other. (We actually use HMAC-SHA256 on the GPT partition type for /var, keyed by the machine-id, since machine-id is something we want to keep somewhat private). Setting the right UUID for installations takes extra care. To make things a bit simpler to set up, we avoid this safety check for nspawn and RootImage= in unit files, under the assumption that such container and service images unlikely will have multiple installations on them. The check is hence only required when booting full machines, i.e. in in systemd-gpt-auto-generator. To help with putting together images for full machines, PR #14368 introduces a repartition tool that can automatically fill in correctly calculated UUIDs on first boot if images have the var partition UUID initialized to all zeroes. With that in place systems can be put together in a way that on first boot the machine ID is determined and the partition table automatically adjusted to have the /var partition with the right UUID.
2019-12-18 12:22:40 +01:00
DISSECT_IMAGE_RELAX_VAR_CHECK = 1 << 10, /* Don't insist that the UUID of /var is hashed from /etc/machine-id */
DISSECT_IMAGE_FSCK = 1 << 11, /* File system check the partition before mounting (no effect when combined with DISSECT_IMAGE_READ_ONLY) */
DISSECT_IMAGE_NO_PARTITION_TABLE = 1 << 12, /* Only recognize single file system images */
DISSECT_IMAGE_VERITY_SHARE = 1 << 13, /* When activating a verity device, reuse existing one if already open */
DISSECT_IMAGE_MKDIR = 1 << 14, /* Make directory to mount right before mounting, if missing */
} DissectImageFlags;
struct DissectedImage {
bool encrypted:1;
bool verity:1; /* verity available and usable */
bool can_verity:1; /* verity available, but not necessarily used */
bool single_file_system:1; /* MBR/GPT or single file system */
DissectedPartition partitions[_PARTITION_DESIGNATOR_MAX];
char *hostname;
sd_id128_t machine_id;
char **machine_info;
char **os_release;
};
struct MountOptions {
unsigned partition_number;
char *options;
LIST_FIELDS(MountOptions, mount_options);
};
MountOptions* mount_options_free_all(MountOptions *options);
DEFINE_TRIVIAL_CLEANUP_FUNC(MountOptions*, mount_options_free_all);
const char* mount_options_from_part(const MountOptions *options, unsigned int partition_number);
int probe_filesystem(const char *node, char **ret_fstype);
int dissect_image(int fd, const void *root_hash, size_t root_hash_size, const char *verity_data, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret);
int dissect_image_and_warn(int fd, const char *name, const void *root_hash, size_t root_hash_size, const char *verity_data, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret);
DissectedImage* dissected_image_unref(DissectedImage *m);
DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref);
int dissected_image_decrypt(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, const char *verity_data, const char *root_hash_sig_path, const void *root_hash_sig, size_t root_hash_sig_size, DissectImageFlags flags, DecryptedImage **ret);
int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, const char *verity_data, const char *root_hash_sig_path, const void *root_hash_sig, size_t root_hash_sig_size, DissectImageFlags flags, DecryptedImage **ret);
int dissected_image_mount(DissectedImage *m, const char *dest, uid_t uid_shift, DissectImageFlags flags);
int dissected_image_mount_and_warn(DissectedImage *m, const char *where, uid_t uid_shift, DissectImageFlags flags);
int dissected_image_acquire_metadata(DissectedImage *m);
DecryptedImage* decrypted_image_unref(DecryptedImage *p);
DEFINE_TRIVIAL_CLEANUP_FUNC(DecryptedImage*, decrypted_image_unref);
int decrypted_image_relinquish(DecryptedImage *d);
const char* partition_designator_to_string(int i) _const_;
int partition_designator_from_string(const char *name) _pure_;
int verity_metadata_load(const char *image, const char *root_hash_path, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data, char **ret_roothashsig);
bool dissected_image_can_do_verity(const DissectedImage *image, unsigned partition_designator);
bool dissected_image_has_verity(const DissectedImage *image, unsigned partition_designator);
int mount_image_privately_interactively(const char *path, DissectImageFlags flags, char **ret_directory, LoopDevice **ret_loop_device, DecryptedImage **ret_decrypted_image);