cryptsetup: add a configurable token waiting timeout

Let's add  configurable timeout how long to wait for FIDO2/PKCS#11
devices to show up. Once the timeout is hit, let's automatically revert
to querying via passphrase.

Fixes: #19739
This commit is contained in:
Lennart Poettering 2021-10-08 22:11:06 +02:00
parent 40091021c3
commit 5cbe70af02

View File

@ -83,6 +83,7 @@ static char *arg_tpm2_device = NULL;
static bool arg_tpm2_device_auto = false;
static uint32_t arg_tpm2_pcr_mask = UINT32_MAX;
static bool arg_headless = false;
static usec_t arg_token_timeout_usec = 30*USEC_PER_SEC;
STATIC_DESTRUCTOR_REGISTER(arg_cipher, freep);
STATIC_DESTRUCTOR_REGISTER(arg_hash, freep);
@ -410,7 +411,15 @@ static int parse_one_option(const char *option) {
} else if (streq(option, "headless"))
arg_headless = true;
else if (!streq(option, "x-initrd.attach"))
else if ((val = startswith(option, "token-timeout="))) {
r = parse_sec_fix_0(val, &arg_token_timeout_usec);
if (r < 0) {
log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
return 0;
}
} else if (!streq(option, "x-initrd.attach"))
log_warning("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
return 0;
@ -711,11 +720,25 @@ static char *make_bindname(const char *volume) {
return s;
}
static int make_security_device_monitor(sd_event *event, sd_device_monitor **ret) {
static int make_security_device_monitor(
sd_event **ret_event,
sd_device_monitor **ret_monitor) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
int r;
assert(ret);
assert(ret_event);
assert(ret_monitor);
/* Waits for a device with "security-device" tag to show up in udev */
r = sd_event_default(&event);
if (r < 0)
return log_error_errno(r, "Failed to allocate event loop: %m");
r = sd_event_add_time_relative(event, NULL, CLOCK_MONOTONIC, arg_token_timeout_usec, USEC_PER_SEC, NULL, INT_TO_PTR(-ETIMEDOUT));
if (r < 0)
return log_error_errno(r, "Failed to install timeout event source: %m");
r = sd_device_monitor_new(&monitor);
if (r < 0)
@ -733,10 +756,49 @@ static int make_security_device_monitor(sd_event *event, sd_device_monitor **ret
if (r < 0)
return log_error_errno(r, "Failed to start device monitor: %m");
*ret = TAKE_PTR(monitor);
*ret_event = TAKE_PTR(event);
*ret_monitor = TAKE_PTR(monitor);
return 0;
}
static int run_security_device_monitor(
sd_event *event,
sd_device_monitor *monitor) {
bool processed = false;
int r;
assert(event);
assert(monitor);
/* Runs the event loop for the device monitor until either something happens, or the time-out is
* hit. */
for (;;) {
int x;
r = sd_event_get_exit_code(event, &x);
if (r < 0) {
if (r != -ENODATA)
return log_error_errno(r, "Failed to query exit code from event loop: %m");
/* On ENODATA we aren't told to exit yet. */
} else {
assert(x == -ETIMEDOUT);
return log_notice_errno(SYNTHETIC_ERRNO(EAGAIN),
"Timed out waiting for security device, aborting security device based authentication attempt.");
}
/* Wait for one event, and then eat all subsequent events until there are no further ones */
r = sd_event_run(event, processed ? 0 : UINT64_MAX);
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");
if (r == 0) /* no events queued anymore */
return 0;
processed = true;
}
}
static bool libcryptsetup_plugins_support(void) {
#if HAVE_LIBCRYPTSETUP_PLUGINS
int r;
@ -906,8 +968,6 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
return log_oom();
for (;;) {
bool processed = false;
if (use_libcryptsetup_plugin && !arg_fido2_cid) {
r = attach_luks2_by_fido2(cd, name, until, arg_headless, arg_fido2_device, flags);
if (IN_SET(r, -ENOTUNIQ, -ENXIO, -ENOENT))
@ -941,11 +1001,7 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
assert(!event);
r = sd_event_default(&event);
if (r < 0)
return log_error_errno(r, "Failed to allocate event loop: %m");
r = make_security_device_monitor(event, &monitor);
r = make_security_device_monitor(&event, &monitor);
if (r < 0)
return r;
@ -956,17 +1012,9 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
continue;
}
for (;;) {
/* Wait for one event, and then eat all subsequent events until there are no
* further ones */
r = sd_event_run(event, processed ? 0 : UINT64_MAX);
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");
if (r == 0)
break;
processed = true;
}
r = run_security_device_monitor(event, monitor);
if (r < 0)
return r;
log_debug("Got one or more potentially relevant udev events, rescanning FIDO2...");
}
@ -1069,8 +1117,6 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
return log_oom();
for (;;) {
bool processed = false;
if (use_libcryptsetup_plugin && arg_pkcs11_uri_auto)
r = attach_luks2_by_pkcs11(cd, name, friendly, until, arg_headless, flags);
else {
@ -1096,11 +1142,7 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
assert(!event);
r = sd_event_default(&event);
if (r < 0)
return log_error_errno(r, "Failed to allocate event loop: %m");
r = make_security_device_monitor(event, &monitor);
r = make_security_device_monitor(&event, &monitor);
if (r < 0)
return r;
@ -1112,17 +1154,9 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
continue;
}
for (;;) {
/* Wait for one event, and then eat all subsequent events until there are no
* further ones */
r = sd_event_run(event, processed ? 0 : UINT64_MAX);
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");
if (r == 0)
break;
processed = true;
}
r = run_security_device_monitor(event, monitor);
if (r < 0)
return r;
log_debug("Got one or more potentially relevant udev events, rescanning PKCS#11...");
}
@ -1157,11 +1191,24 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
return 0;
}
static int make_tpm2_device_monitor(sd_event *event, sd_device_monitor **ret) {
static int make_tpm2_device_monitor(
sd_event **ret_event,
sd_device_monitor **ret_monitor) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
int r;
assert(ret);
assert(ret_event);
assert(ret_monitor);
r = sd_event_default(&event);
if (r < 0)
return log_error_errno(r, "Failed to allocate event loop: %m");
r = sd_event_add_time_relative(event, NULL, CLOCK_MONOTONIC, arg_token_timeout_usec, USEC_PER_SEC, NULL, INT_TO_PTR(-ETIMEDOUT));
if (r < 0)
return log_error_errno(r, "Failed to install timeout event source: %m");
r = sd_device_monitor_new(&monitor);
if (r < 0)
@ -1179,7 +1226,8 @@ static int make_tpm2_device_monitor(sd_event *event, sd_device_monitor **ret) {
if (r < 0)
return log_error_errno(r, "Failed to start device monitor: %m");
*ret = TAKE_PTR(monitor);
*ret_event = TAKE_PTR(event);
*ret_monitor = TAKE_PTR(monitor);
return 0;
}
@ -1236,8 +1284,6 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
return log_oom();
for (;;) {
bool processed = false;
if (key_file || key_data) {
/* If key data is specified, use that */
@ -1341,11 +1387,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
return log_notice_errno(SYNTHETIC_ERRNO(EAGAIN),
"No TPM2 hardware discovered and EFI bios indicates no support for it either, assuming TPM2-less system, falling back to traditional unocking.");
r = sd_event_default(&event);
if (r < 0)
return log_error_errno(r, "Failed to allocate event loop: %m");
r = make_tpm2_device_monitor(event, &monitor);
r = make_tpm2_device_monitor(&event, &monitor);
if (r < 0)
return r;
@ -1356,17 +1398,9 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
continue;
}
for (;;) {
/* Wait for one event, and then eat all subsequent events until there are no
* further ones */
r = sd_event_run(event, processed ? 0 : UINT64_MAX);
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");
if (r == 0)
break;
processed = true;
}
r = run_security_device_monitor(event, monitor);
if (r < 0)
return r;
log_debug("Got one or more potentially relevant udev events, rescanning for TPM2...");
}