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