mirror of
https://github.com/systemd/systemd.git
synced 2024-11-05 06:52:22 +03:00
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.
This commit is contained in:
parent
4171837be6
commit
d4dffb8533
@ -2581,7 +2581,7 @@ static int apply_mount_namespace(
|
||||
needs_sandboxing ? context->protect_home : PROTECT_HOME_NO,
|
||||
needs_sandboxing ? context->protect_system : PROTECT_SYSTEM_NO,
|
||||
context->mount_flags,
|
||||
DISSECT_IMAGE_DISCARD_ON_LOOP,
|
||||
DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK,
|
||||
error_path);
|
||||
|
||||
/* If we couldn't set up the namespace this is probably due to a missing capability. setup_namespace() reports
|
||||
|
@ -22,7 +22,7 @@ static enum {
|
||||
} arg_action = ACTION_DISSECT;
|
||||
static const char *arg_image = NULL;
|
||||
static const char *arg_path = NULL;
|
||||
static DissectImageFlags arg_flags = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP;
|
||||
static DissectImageFlags arg_flags = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK;
|
||||
static void *arg_root_hash = NULL;
|
||||
static size_t arg_root_hash_size = 0;
|
||||
|
||||
|
@ -697,6 +697,18 @@ static int enumerate_partitions(dev_t devnum) {
|
||||
r = k;
|
||||
}
|
||||
|
||||
if (m->partitions[PARTITION_VAR].found) {
|
||||
k = add_partition_mount(m->partitions + PARTITION_VAR, "var", "/var", "Variable Data Partition");
|
||||
if (k < 0)
|
||||
r = k;
|
||||
}
|
||||
|
||||
if (m->partitions[PARTITION_TMP].found) {
|
||||
k = add_partition_mount(m->partitions + PARTITION_TMP, "var-tmp", "/var/tmp", "Temporary Data Partition");
|
||||
if (k < 0)
|
||||
r = k;
|
||||
}
|
||||
|
||||
if (m->partitions[PARTITION_ROOT].found) {
|
||||
k = add_root_rw(m->partitions + PARTITION_ROOT);
|
||||
if (k < 0)
|
||||
|
@ -5058,7 +5058,7 @@ static int run(int argc, char *argv[]) {
|
||||
loop->fd,
|
||||
arg_image,
|
||||
arg_root_hash, arg_root_hash_size,
|
||||
DISSECT_IMAGE_REQUIRE_ROOT,
|
||||
DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK,
|
||||
&dissected_image);
|
||||
if (r == -ENOPKG) {
|
||||
/* dissected_image_and_warn() already printed a brief error message. Extend on that with more details */
|
||||
|
@ -387,7 +387,7 @@ static int portable_extract_by_path(
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to create temporary directory: %m");
|
||||
|
||||
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP, &m);
|
||||
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
|
||||
if (r == -ENOPKG)
|
||||
sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Couldn't identify a suitable partition table or file system in '%s'.", path);
|
||||
else if (r == -EADDRNOTAVAIL)
|
||||
|
@ -598,6 +598,43 @@ int dissect_image(
|
||||
if (!generic_node)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
} else if (sd_id128_equal(type_id, GPT_TMP)) {
|
||||
|
||||
if (pflags & GPT_FLAG_NO_AUTO)
|
||||
continue;
|
||||
|
||||
designator = PARTITION_TMP;
|
||||
rw = !(pflags & GPT_FLAG_READ_ONLY);
|
||||
|
||||
} else if (sd_id128_equal(type_id, GPT_VAR)) {
|
||||
|
||||
if (pflags & GPT_FLAG_NO_AUTO)
|
||||
continue;
|
||||
|
||||
if (!FLAGS_SET(flags, DISSECT_IMAGE_RELAX_VAR_CHECK)) {
|
||||
sd_id128_t var_uuid;
|
||||
|
||||
/* For /var we insist that the uuid of the partition matches the
|
||||
* HMAC-SHA256 of the /var GPT partition type uuid, keyed by machine
|
||||
* ID. Why? Unlike the other partitions /var is inherently
|
||||
* installation specific, hence we need to be careful not to mount it
|
||||
* in the wrong installation. By hashing the partition UUID from
|
||||
* /etc/machine-id we can securely bind the partition to the
|
||||
* installation. */
|
||||
|
||||
r = sd_id128_get_machine_app_specific(GPT_VAR, &var_uuid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!sd_id128_equal(var_uuid, id)) {
|
||||
log_debug("Found a /var/ partition, but its UUID didn't match our expectations, ignoring.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
designator = PARTITION_VAR;
|
||||
rw = !(pflags & GPT_FLAG_READ_ONLY);
|
||||
}
|
||||
|
||||
if (designator != _PARTITION_DESIGNATOR_INVALID) {
|
||||
@ -910,6 +947,14 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = mount_partition(m->partitions + PARTITION_VAR, where, "/var", uid_shift, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = mount_partition(m->partitions + PARTITION_TMP, where, "/var/tmp", uid_shift, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
boot_mounted = mount_partition(m->partitions + PARTITION_XBOOTLDR, where, "/boot", uid_shift, flags);
|
||||
if (boot_mounted < 0)
|
||||
return boot_mounted;
|
||||
@ -1333,7 +1378,8 @@ int dissected_image_acquire_metadata(DissectedImage *m) {
|
||||
[META_HOSTNAME] = "/etc/hostname\0",
|
||||
[META_MACHINE_ID] = "/etc/machine-id\0",
|
||||
[META_MACHINE_INFO] = "/etc/machine-info\0",
|
||||
[META_OS_RELEASE] = "/etc/os-release\0/usr/lib/os-release\0",
|
||||
[META_OS_RELEASE] = "/etc/os-release\0"
|
||||
"/usr/lib/os-release\0",
|
||||
};
|
||||
|
||||
_cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL;
|
||||
@ -1528,6 +1574,8 @@ static const char *const partition_designator_table[] = {
|
||||
[PARTITION_SWAP] = "swap",
|
||||
[PARTITION_ROOT_VERITY] = "root-verity",
|
||||
[PARTITION_ROOT_SECONDARY_VERITY] = "root-secondary-verity",
|
||||
[PARTITION_TMP] = "tmp",
|
||||
[PARTITION_VAR] = "var",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(partition_designator, int);
|
||||
|
@ -33,6 +33,8 @@ enum {
|
||||
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_TMP,
|
||||
PARTITION_VAR,
|
||||
_PARTITION_DESIGNATOR_MAX,
|
||||
_PARTITION_DESIGNATOR_INVALID = -1
|
||||
};
|
||||
@ -59,6 +61,7 @@ typedef enum DissectImageFlags {
|
||||
DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY = 1 << 7, /* Mount only non-root 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 */
|
||||
} DissectImageFlags;
|
||||
|
||||
struct DissectedImage {
|
||||
|
@ -19,6 +19,8 @@
|
||||
#define GPT_SWAP SD_ID128_MAKE(06,57,fd,6d,a4,ab,43,c4,84,e5,09,33,c8,4b,4f,4f)
|
||||
#define GPT_HOME SD_ID128_MAKE(93,3a,c7,e1,2e,b4,4f,13,b8,44,0e,14,e2,ae,f9,15)
|
||||
#define GPT_SRV SD_ID128_MAKE(3b,8f,84,25,20,e0,4f,3b,90,7f,1a,25,a7,6f,98,e8)
|
||||
#define GPT_VAR SD_ID128_MAKE(4d,21,b0,16,b5,34,45,c2,a9,fb,5c,16,e0,91,fd,2d)
|
||||
#define GPT_TMP SD_ID128_MAKE(7e,c6,f5,57,3b,c5,4a,ca,b2,93,16,ef,5d,f6,39,d1)
|
||||
|
||||
/* 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). */
|
||||
|
@ -1171,7 +1171,7 @@ int image_read_metadata(Image *i) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT, &m);
|
||||
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -28,7 +28,7 @@ int main(int argc, char *argv[]) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT, &m);
|
||||
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to dissect image: %m");
|
||||
return EXIT_FAILURE;
|
||||
|
Loading…
Reference in New Issue
Block a user