]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
hibernate-resume: automatically decrypt dissected swap if told so via autoSwap 37335/head
authorMike Yuan <me@yhndnzj.com>
Sat, 3 May 2025 16:41:00 +0000 (18:41 +0200)
committerMike Yuan <me@yhndnzj.com>
Mon, 5 May 2025 17:37:11 +0000 (19:37 +0200)
With the addition of /dev/disk/by-designator/ along with
ID_DISSECT_PART_DESIGNATOR attr, it is now trivial to tell
whether the swap device we hibernated into is the "auto" one.
Hence use that bit of info and generate cryptsetup unit
in hibernate-resume-generator if that's the case.

Ideally, gpt-auto should really just handle swap already
in initrd, which would save us a myriad of trouble and
the system behaves more consistently. But I don't see that
happening anytime soon. This is the second best option
we have I reckon.

Closes #27247 (#35328, #37330)

src/hibernate-resume/hibernate-resume-config.c
src/hibernate-resume/hibernate-resume-config.h
src/hibernate-resume/hibernate-resume-generator.c

index ed064ea4153aa846eeedd993fcdf5065c0f01d09..3289fcd52166a5a98e7f46d079f5839d3c05d477 100644 (file)
@@ -143,13 +143,14 @@ static bool validate_efi_hibernate_location(EFIHibernateLocation *e) {
 int get_efi_hibernate_location(EFIHibernateLocation **ret) {
 #if ENABLE_EFI
         static const sd_json_dispatch_field dispatch_table[] = {
-                { "uuid",                  SD_JSON_VARIANT_STRING,        sd_json_dispatch_id128,  offsetof(EFIHibernateLocation, uuid),           SD_JSON_MANDATORY                },
-                { "offset",                _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(EFIHibernateLocation, offset),         SD_JSON_MANDATORY                },
-                { "kernelVersion",         SD_JSON_VARIANT_STRING,        sd_json_dispatch_string, offsetof(EFIHibernateLocation, kernel_version), SD_JSON_PERMISSIVE               },
-                { "osReleaseId",           SD_JSON_VARIANT_STRING,        sd_json_dispatch_string, offsetof(EFIHibernateLocation, id),             SD_JSON_PERMISSIVE               },
-                { "osReleaseImageId",      SD_JSON_VARIANT_STRING,        sd_json_dispatch_string, offsetof(EFIHibernateLocation, image_id),       SD_JSON_PERMISSIVE               },
-                { "osReleaseVersionId",    SD_JSON_VARIANT_STRING,        sd_json_dispatch_string, offsetof(EFIHibernateLocation, version_id),     SD_JSON_PERMISSIVE|SD_JSON_DEBUG },
-                { "osReleaseImageVersion", SD_JSON_VARIANT_STRING,        sd_json_dispatch_string, offsetof(EFIHibernateLocation, image_version),  SD_JSON_PERMISSIVE|SD_JSON_DEBUG },
+                { "uuid",                  SD_JSON_VARIANT_STRING,        sd_json_dispatch_id128,   offsetof(EFIHibernateLocation, uuid),           SD_JSON_MANDATORY                },
+                { "offset",                _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64,  offsetof(EFIHibernateLocation, offset),         SD_JSON_MANDATORY                },
+                { "autoSwap",              SD_JSON_VARIANT_BOOLEAN,       sd_json_dispatch_stdbool, offsetof(EFIHibernateLocation, auto_swap),      0                                },
+                { "kernelVersion",         SD_JSON_VARIANT_STRING,        sd_json_dispatch_string,  offsetof(EFIHibernateLocation, kernel_version), SD_JSON_PERMISSIVE               },
+                { "osReleaseId",           SD_JSON_VARIANT_STRING,        sd_json_dispatch_string,  offsetof(EFIHibernateLocation, id),             SD_JSON_PERMISSIVE               },
+                { "osReleaseImageId",      SD_JSON_VARIANT_STRING,        sd_json_dispatch_string,  offsetof(EFIHibernateLocation, image_id),       SD_JSON_PERMISSIVE               },
+                { "osReleaseVersionId",    SD_JSON_VARIANT_STRING,        sd_json_dispatch_string,  offsetof(EFIHibernateLocation, version_id),     SD_JSON_PERMISSIVE|SD_JSON_DEBUG },
+                { "osReleaseImageVersion", SD_JSON_VARIANT_STRING,        sd_json_dispatch_string,  offsetof(EFIHibernateLocation, image_version),  SD_JSON_PERMISSIVE|SD_JSON_DEBUG },
                 {},
         };
 
index 24cc8dd2a47de92d15795310f03d23d47d3e3f5e..4bf4af6386305e643f0e295d41617e0cffff7400 100644 (file)
@@ -16,6 +16,10 @@ typedef struct EFIHibernateLocation {
         sd_id128_t uuid;
         uint64_t offset;
 
+        /* Whether the device we hibernated into is the "auto" one, i.e. will show up as
+         * /dev/disk/by-designator/swap(-luks). */
+        bool auto_swap;
+
         char *kernel_version;
         char *id;
         char *image_id;
index 666cd52e477545a4a4a2f98b2f5b944364e69b5c..8d268a4805124eb1de9e2c3911c247a1d6ef78e3 100644 (file)
@@ -2,6 +2,9 @@
 
 #include "alloc-util.h"
 #include "dropin.h"
+#include "efi-loader.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "generator.h"
 #include "hibernate-resume-config.h"
 #include "initrd-util.h"
@@ -15,6 +18,7 @@
 #include "unit-name.h"
 
 static const char *arg_dest = NULL;
+static const char *arg_dest_late = NULL;
 static char *arg_resume_options = NULL;
 static char *arg_root_options = NULL;
 static bool arg_noresume = false;
@@ -54,6 +58,58 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
         return 0;
 }
 
+#define DISSECTED_SWAP_LUKS_DEVICE      "/dev/disk/by-designator/swap-luks"
+#define DISSECTED_SWAP_LUKS_DEVICE_UNIT "dev-disk-by\\x2ddesignator-swap\\x2dluks.device"
+
+static int add_dissected_swap_cryptsetup(void) {
+
+#if HAVE_LIBCRYPTSETUP
+        _cleanup_fclose_ FILE *f = NULL;
+        int r;
+
+        /* Write out cryptsetup unit for the "auto" swap device (/dev/disk/by-designator/swap-luks), so that
+         * resume from hibernation can be automatically initiated there. This mostly follows what gpt-auto does,
+         * but operates in initrd. */
+
+        r = generator_open_unit_file(arg_dest_late, /* source = */ NULL, "systemd-cryptsetup@swap.service", &f);
+        if (r < 0)
+                return r;
+
+        r = generator_write_cryptsetup_unit_section(f, /* source = */ NULL);
+        if (r < 0)
+                return r;
+
+        fputs("Before=umount.target cryptsetup.target\n"
+              "Conflicts=umount.target\n"
+              "BindsTo="DISSECTED_SWAP_LUKS_DEVICE_UNIT"\n"
+              "After="DISSECTED_SWAP_LUKS_DEVICE_UNIT"\n",
+              f);
+
+        r = generator_write_cryptsetup_service_section(
+                        f, "swap", DISSECTED_SWAP_LUKS_DEVICE,
+                        /* key_file = */ NULL,
+                        efi_measured_uki(LOG_DEBUG) > 0 ? "tpm2-device=auto" : NULL);
+        if (r < 0)
+                return r;
+
+        r = fflush_and_check(f);
+        if (r < 0)
+                return log_error_errno(r, "Failed to write cryptsetup unit for " DISSECTED_SWAP_LUKS_DEVICE ": %m");
+
+        r = generator_write_device_timeout(arg_dest_late,
+                                           DISSECTED_SWAP_LUKS_DEVICE,
+                                           arg_resume_options ?: arg_root_options, /* filtered = */ NULL);
+        if (r < 0)
+                return r;
+
+        return generator_add_symlink(arg_dest_late, DISSECTED_SWAP_LUKS_DEVICE_UNIT, "wants", "systemd-cryptsetup@swap.service");
+#else
+        return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                               "systemd-hibernate-resume-generator was compiled without libcryptsetup support, "
+                               "not generating cryptsetup unit for " DISSECTED_SWAP_LUKS_DEVICE ".");
+#endif
+}
+
 static int process_resume(const HibernateInfo *info) {
         _cleanup_free_ char *device_unit = NULL;
         int r;
@@ -89,6 +145,12 @@ static int process_resume(const HibernateInfo *info) {
         if (r < 0)
                 return log_error_errno(r, "Failed to write device dependency drop-in: %m");
 
+        /* Generate cryptsetup unit for /dev/disk/by-designator/swap-luks if we hibernated into it, but only
+         * if resume= is not specified, on the assumption that the user would have everything configured
+         * manually otherwise. */
+        if (!info->cmdline && info->efi->auto_swap)
+                (void) add_dissected_swap_cryptsetup();
+
         return generator_add_symlink(arg_dest, SPECIAL_SYSINIT_TARGET, "wants", SPECIAL_HIBERNATE_RESUME_SERVICE);
 }
 
@@ -97,6 +159,7 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
         int r;
 
         arg_dest = ASSERT_PTR(dest);
+        arg_dest_late = ASSERT_PTR(dest_late);
 
         /* Don't even consider resuming outside of initrd. */
         if (!in_initrd()) {