From: Lennart Poettering Date: Fri, 8 Oct 2021 20:11:06 +0000 (+0200) Subject: cryptsetup: add a configurable token waiting timeout X-Git-Tag: v250-rc1~535^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5cbe70af0252a5e4eb685303fdba692186811f00;p=thirdparty%2Fsystemd.git 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 --- diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 43c6bf529f8..fc63f8834ef 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -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..."); }