|
|
a9339c |
From aafa651e44df825abeec061f295f227862aad6d9 Mon Sep 17 00:00:00 2001
|
|
|
a9339c |
From: Michal Sekletar <msekleta@redhat.com>
|
|
|
a9339c |
Date: Thu, 30 Aug 2018 08:45:11 +0000
|
|
|
a9339c |
Subject: [PATCH] cryptsetup-generator: introduce basic keydev support
|
|
|
a9339c |
|
|
|
a9339c |
Dracut has a support for unlocking encrypted drives with keyfile stored
|
|
|
a9339c |
on the external drive. This support is included in the generated initrd
|
|
|
a9339c |
only if systemd module is not included.
|
|
|
a9339c |
|
|
|
a9339c |
When systemd is used in initrd then attachment of encrypted drives is
|
|
|
a9339c |
handled by systemd-cryptsetup tools. Our generator has support for
|
|
|
a9339c |
keyfile, however, it didn't support keyfile on the external block
|
|
|
a9339c |
device (keydev).
|
|
|
a9339c |
|
|
|
a9339c |
This commit introduces basic keydev support. Keydev can be specified per
|
|
|
a9339c |
luks.uuid on the kernel command line. Keydev is automatically mounted
|
|
|
a9339c |
during boot and we look for keyfile in the keydev
|
|
|
a9339c |
mountpoint (i.e. keyfile path is prefixed with the keydev mount point
|
|
|
a9339c |
path). After crypt device is attached we automatically unmount
|
|
|
a9339c |
where keyfile resides.
|
|
|
a9339c |
|
|
|
a9339c |
Example:
|
|
|
a9339c |
rd.luks.key=70bc876b-f627-4038-9049-3080d79d2165=/key:LABEL=KEYDEV
|
|
|
a9339c |
|
|
|
a9339c |
(cherry-picked from commit 70f5f48eb891b12e969577b464de61e15a2593da)
|
|
|
a9339c |
|
|
|
a9339c |
Resolves: #1619743
|
|
|
a9339c |
---
|
|
|
a9339c |
man/systemd-cryptsetup-generator.xml | 14 ++++
|
|
|
a9339c |
src/cryptsetup/cryptsetup-generator.c | 122 ++++++++++++++++++++++++++++++++--
|
|
|
a9339c |
2 files changed, 131 insertions(+), 5 deletions(-)
|
|
|
a9339c |
|
|
|
a9339c |
diff --git a/man/systemd-cryptsetup-generator.xml b/man/systemd-cryptsetup-generator.xml
|
|
|
a9339c |
index b6270358e..8cfd8b6a8 100644
|
|
|
a9339c |
--- a/man/systemd-cryptsetup-generator.xml
|
|
|
a9339c |
+++ b/man/systemd-cryptsetup-generator.xml
|
|
|
a9339c |
@@ -168,6 +168,20 @@
|
|
|
a9339c |
to the one specified by <varname>rd.luks.key=</varname> or
|
|
|
a9339c |
<varname>luks.key=</varname> of the corresponding UUID, or the
|
|
|
a9339c |
password file that was specified without a UUID.</para>
|
|
|
a9339c |
+
|
|
|
a9339c |
+ <para>It is also possible to specify an external device which
|
|
|
a9339c |
+ should be mounted before we attempt to unlock the LUKS device.
|
|
|
a9339c |
+ systemd-cryptsetup will use password file stored on that
|
|
|
a9339c |
+ device. Device containing password file is specified by
|
|
|
a9339c |
+ appending colon and a device identifier to the password file
|
|
|
a9339c |
+ path. For example,
|
|
|
a9339c |
+ <varname>rd.luks.uuid=</varname>b40f1abf-2a53-400a-889a-2eccc27eaa40
|
|
|
a9339c |
+ <varname>rd.luks.key=</varname>b40f1abf-2a53-400a-889a-2eccc27eaa40=/keyfile:LABEL=keydev.
|
|
|
a9339c |
+ Hence, in this case, we will attempt to mount file system
|
|
|
a9339c |
+ residing on the block device with label <literal>keydev</literal>.
|
|
|
a9339c |
+ This syntax is for now only supported on a per-device basis,
|
|
|
a9339c |
+ i.e. you have to specify LUKS device UUID.</para>
|
|
|
a9339c |
+
|
|
|
a9339c |
<para><varname>rd.luks.key=</varname>
|
|
|
a9339c |
is honored only by initial RAM disk
|
|
|
a9339c |
(initrd) while
|
|
|
a9339c |
diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c
|
|
|
a9339c |
index 5f29093f5..42c30c5ca 100644
|
|
|
a9339c |
--- a/src/cryptsetup/cryptsetup-generator.c
|
|
|
a9339c |
+++ b/src/cryptsetup/cryptsetup-generator.c
|
|
|
a9339c |
@@ -38,6 +38,7 @@
|
|
|
a9339c |
typedef struct crypto_device {
|
|
|
a9339c |
char *uuid;
|
|
|
a9339c |
char *keyfile;
|
|
|
a9339c |
+ char *keydev;
|
|
|
a9339c |
char *name;
|
|
|
a9339c |
char *options;
|
|
|
a9339c |
bool create;
|
|
|
a9339c |
@@ -51,14 +52,79 @@ static Hashmap *arg_disks = NULL;
|
|
|
a9339c |
static char *arg_default_options = NULL;
|
|
|
a9339c |
static char *arg_default_keyfile = NULL;
|
|
|
a9339c |
|
|
|
a9339c |
+static int generate_keydev_mount(const char *name, const char *keydev, char **unit, char **mount) {
|
|
|
a9339c |
+ _cleanup_free_ char *u = NULL, *what = NULL, *where = NULL, *p = NULL;
|
|
|
a9339c |
+ _cleanup_fclose_ FILE *f = NULL;
|
|
|
a9339c |
+ int r;
|
|
|
a9339c |
+
|
|
|
a9339c |
+ assert(name);
|
|
|
a9339c |
+ assert(keydev);
|
|
|
a9339c |
+ assert(unit);
|
|
|
a9339c |
+ assert(mount);
|
|
|
a9339c |
+
|
|
|
a9339c |
+ r = mkdir_parents("/run/systemd/cryptsetup", 0755);
|
|
|
a9339c |
+ if (r < 0)
|
|
|
a9339c |
+ return r;
|
|
|
a9339c |
+
|
|
|
a9339c |
+ r = mkdir("/run/systemd/cryptsetup", 0700);
|
|
|
a9339c |
+ if (r < 0)
|
|
|
a9339c |
+ return r;
|
|
|
a9339c |
+
|
|
|
a9339c |
+ where = strjoin("/run/systemd/cryptsetup/keydev-", name, NULL);
|
|
|
a9339c |
+ if (!where)
|
|
|
a9339c |
+ return -ENOMEM;
|
|
|
a9339c |
+
|
|
|
a9339c |
+ r = mkdir(where, 0700);
|
|
|
a9339c |
+ if (r < 0)
|
|
|
a9339c |
+ return r;
|
|
|
a9339c |
+
|
|
|
a9339c |
+ u = unit_name_from_path(where, ".mount");
|
|
|
a9339c |
+ if (!u)
|
|
|
a9339c |
+ return -ENOMEM;
|
|
|
a9339c |
+
|
|
|
a9339c |
+ what = fstab_node_to_udev_node(keydev);
|
|
|
a9339c |
+ if (!what)
|
|
|
a9339c |
+ return -ENOMEM;
|
|
|
a9339c |
+
|
|
|
a9339c |
+ p = strjoin(arg_dest, "/", u, NULL);
|
|
|
a9339c |
+ if (!p)
|
|
|
a9339c |
+ return log_oom();
|
|
|
a9339c |
+
|
|
|
a9339c |
+ f = fopen(p, "wxe");
|
|
|
a9339c |
+ if (!f)
|
|
|
a9339c |
+ return log_error_errno(errno, "Failed to create unit file %s: %m", p);
|
|
|
a9339c |
+
|
|
|
a9339c |
+ fprintf(f,
|
|
|
a9339c |
+ "# Automatically generated by systemd-cryptsetup-generator\n\n"
|
|
|
a9339c |
+ "[Unit]\n"
|
|
|
a9339c |
+ "DefaultDependencies=no\n\n"
|
|
|
a9339c |
+ "[Mount]\n"
|
|
|
a9339c |
+ "What=%s\n"
|
|
|
a9339c |
+ "Where=%s\n"
|
|
|
a9339c |
+ "Options=ro\n", what, where);
|
|
|
a9339c |
+
|
|
|
a9339c |
+ r = fflush_and_check(f);
|
|
|
a9339c |
+ if (r < 0)
|
|
|
a9339c |
+ return r;
|
|
|
a9339c |
+
|
|
|
a9339c |
+ *unit = u;
|
|
|
a9339c |
+ u = NULL;
|
|
|
a9339c |
+
|
|
|
a9339c |
+ *mount = where;
|
|
|
a9339c |
+ where = NULL;
|
|
|
a9339c |
+
|
|
|
a9339c |
+ return 0;
|
|
|
a9339c |
+}
|
|
|
a9339c |
+
|
|
|
a9339c |
static int create_disk(
|
|
|
a9339c |
const char *name,
|
|
|
a9339c |
const char *device,
|
|
|
a9339c |
+ const char *keydev,
|
|
|
a9339c |
const char *password,
|
|
|
a9339c |
const char *options) {
|
|
|
a9339c |
|
|
|
a9339c |
_cleanup_free_ char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *to = NULL, *e = NULL,
|
|
|
a9339c |
- *filtered = NULL;
|
|
|
a9339c |
+ *filtered = NULL, *keydev_mount = NULL, *keyfile_path = NULL;
|
|
|
a9339c |
_cleanup_fclose_ FILE *f = NULL;
|
|
|
a9339c |
bool noauto, nofail, tmp, swap, netdev;
|
|
|
a9339c |
char *from;
|
|
|
a9339c |
@@ -98,6 +164,9 @@ static int create_disk(
|
|
|
a9339c |
if (!d)
|
|
|
a9339c |
return log_oom();
|
|
|
a9339c |
|
|
|
a9339c |
+ if (keydev && !password)
|
|
|
a9339c |
+ return log_error_errno(-EINVAL, "Keydev is specified, but path to the password file is missing: %m");
|
|
|
a9339c |
+
|
|
|
a9339c |
f = fopen(p, "wxe");
|
|
|
a9339c |
if (!f)
|
|
|
a9339c |
return log_error_errno(errno, "Failed to create unit file %s: %m", p);
|
|
|
a9339c |
@@ -115,6 +184,20 @@ static int create_disk(
|
|
|
a9339c |
"After=%s\n",
|
|
|
a9339c |
netdev ? "remote-fs-pre.target" : "cryptsetup-pre.target");
|
|
|
a9339c |
|
|
|
a9339c |
+ if (keydev) {
|
|
|
a9339c |
+ _cleanup_free_ char *unit = NULL;
|
|
|
a9339c |
+
|
|
|
a9339c |
+ r = generate_keydev_mount(name, keydev, &unit, &keydev_mount);
|
|
|
a9339c |
+ if (r < 0)
|
|
|
a9339c |
+ return log_error_errno(r, "Failed to generate keydev mount unit: %m");
|
|
|
a9339c |
+
|
|
|
a9339c |
+ keyfile_path = prefix_root(keydev_mount, password);
|
|
|
a9339c |
+ if (!keyfile_path)
|
|
|
a9339c |
+ return log_oom();
|
|
|
a9339c |
+
|
|
|
a9339c |
+ password = keyfile_path;
|
|
|
a9339c |
+ }
|
|
|
a9339c |
+
|
|
|
a9339c |
if (!nofail)
|
|
|
a9339c |
fprintf(f,
|
|
|
a9339c |
"Before=%s\n",
|
|
|
a9339c |
@@ -181,6 +264,11 @@ static int create_disk(
|
|
|
a9339c |
"ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
|
|
|
a9339c |
name);
|
|
|
a9339c |
|
|
|
a9339c |
+ if (keydev)
|
|
|
a9339c |
+ fprintf(f,
|
|
|
a9339c |
+ "ExecStartPost=/bin/umount '%s'\n\n",
|
|
|
a9339c |
+ keydev_mount);
|
|
|
a9339c |
+
|
|
|
a9339c |
fflush(f);
|
|
|
a9339c |
if (ferror(f))
|
|
|
a9339c |
return log_error_errno(errno, "Failed to write file %s: %m", p);
|
|
|
a9339c |
@@ -248,6 +336,7 @@ static void free_arg_disks(void) {
|
|
|
a9339c |
while ((d = hashmap_steal_first(arg_disks))) {
|
|
|
a9339c |
free(d->uuid);
|
|
|
a9339c |
free(d->keyfile);
|
|
|
a9339c |
+ free(d->keydev);
|
|
|
a9339c |
free(d->name);
|
|
|
a9339c |
free(d->options);
|
|
|
a9339c |
free(d);
|
|
|
a9339c |
@@ -335,13 +424,36 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
|
|
|
a9339c |
|
|
|
a9339c |
r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
|
|
|
a9339c |
if (r == 2) {
|
|
|
a9339c |
+ char *c;
|
|
|
a9339c |
+ _cleanup_free_ char *keyfile = NULL, *keydev = NULL;
|
|
|
a9339c |
+
|
|
|
a9339c |
d = get_crypto_device(uuid);
|
|
|
a9339c |
if (!d)
|
|
|
a9339c |
return log_oom();
|
|
|
a9339c |
|
|
|
a9339c |
+ c = strrchr(uuid_value, ':');
|
|
|
a9339c |
+ if (!c) {
|
|
|
a9339c |
+ free(d->keyfile);
|
|
|
a9339c |
+ d->keyfile = uuid_value;
|
|
|
a9339c |
+ uuid_value = NULL;
|
|
|
a9339c |
+
|
|
|
a9339c |
+ return 0;
|
|
|
a9339c |
+ }
|
|
|
a9339c |
+
|
|
|
a9339c |
+ *c = '\0';
|
|
|
a9339c |
+ keyfile = strdup(uuid_value);
|
|
|
a9339c |
+ keydev = strdup(++c);
|
|
|
a9339c |
+
|
|
|
a9339c |
+ if (!keyfile || !keydev)
|
|
|
a9339c |
+ return log_oom();
|
|
|
a9339c |
+
|
|
|
a9339c |
free(d->keyfile);
|
|
|
a9339c |
- d->keyfile = uuid_value;
|
|
|
a9339c |
- uuid_value = NULL;
|
|
|
a9339c |
+ d->keyfile = keyfile;
|
|
|
a9339c |
+ keyfile = NULL;
|
|
|
a9339c |
+
|
|
|
a9339c |
+ free(d->keydev);
|
|
|
a9339c |
+ d->keydev = keydev;
|
|
|
a9339c |
+ keydev = NULL;
|
|
|
a9339c |
} else if (free_and_strdup(&arg_default_keyfile, value))
|
|
|
a9339c |
return log_oom();
|
|
|
a9339c |
|
|
|
a9339c |
@@ -420,7 +532,7 @@ static int add_crypttab_devices(void) {
|
|
|
a9339c |
continue;
|
|
|
a9339c |
}
|
|
|
a9339c |
|
|
|
a9339c |
- r = create_disk(name, device, keyfile, (d && d->options) ? d->options : options);
|
|
|
a9339c |
+ r = create_disk(name, device, NULL, keyfile, (d && d->options) ? d->options : options);
|
|
|
a9339c |
if (r < 0)
|
|
|
a9339c |
return r;
|
|
|
a9339c |
|
|
|
a9339c |
@@ -460,7 +572,7 @@ static int add_proc_cmdline_devices(void) {
|
|
|
a9339c |
else
|
|
|
a9339c |
options = "timeout=0";
|
|
|
a9339c |
|
|
|
a9339c |
- r = create_disk(d->name, device, d->keyfile ?: arg_default_keyfile, options);
|
|
|
a9339c |
+ r = create_disk(d->name, device, d->keydev, d->keyfile ?: arg_default_keyfile, options);
|
|
|
a9339c |
if (r < 0)
|
|
|
a9339c |
return r;
|
|
|
a9339c |
}
|