From d66894a7a53f0eb26228074ef1b8dcca2a316f87 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 7 Nov 2024 11:38:23 +0100 Subject: [PATCH] ask-password-api: add new "hup_fd" field to AskPasswordReq This new field allows specification of an fd on which the password prompt logic will look for POLLHUP events for, and if seen will abort the query. The usecase for this is that when we query for a pw on behalf of a Varlink client we can abort the query automatically if the client dies. --- src/ask-password/ask-password.c | 1 + src/bootctl/bootctl-install.c | 1 + src/cryptenroll/cryptenroll-password.c | 2 + src/cryptenroll/cryptenroll-tpm2.c | 1 + src/cryptsetup/cryptsetup.c | 2 + src/firstboot/firstboot.c | 1 + src/home/homectl.c | 4 + src/keyutil/keyutil.c | 2 + src/measure/measure.c | 1 + src/pcrlock/pcrlock.c | 1 + src/repart/repart.c | 1 + src/sbsign/sbsign.c | 1 + src/shared/ask-password-api.c | 83 +++++++++++++++---- src/shared/ask-password-api.h | 1 + src/shared/cryptsetup-fido2.c | 1 + src/shared/cryptsetup-tpm2.c | 1 + src/shared/dissect-image.c | 1 + src/shared/libfido2-util.c | 1 + src/shared/pkcs11-util.c | 1 + src/test/test-ask-password-api.c | 1 + .../tty-ask-password-agent.c | 2 + 21 files changed, 96 insertions(+), 14 deletions(-) diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c index d3afc37781..154aaa030e 100644 --- a/src/ask-password/ask-password.c +++ b/src/ask-password/ask-password.c @@ -259,6 +259,7 @@ static int run(int argc, char *argv[]) { .keyring = arg_key_name, .credential = arg_credential_name ?: "password", .until = timeout, + .hup_fd = -EBADF, }; r = ask_password_auto(&req, arg_flags, &l); diff --git a/src/bootctl/bootctl-install.c b/src/bootctl/bootctl-install.c index 76deba56e7..884521bcfa 100644 --- a/src/bootctl/bootctl-install.c +++ b/src/bootctl/bootctl-install.c @@ -989,6 +989,7 @@ int verb_install(int argc, char *argv[], void *userdata) { .keyring = arg_private_key, .credential = "bootctl.private-key-pin", .until = USEC_INFINITY, + .hup_fd = -EBADF, }, &private_key, &ui); diff --git a/src/cryptenroll/cryptenroll-password.c b/src/cryptenroll/cryptenroll-password.c index 56a3bb4456..c6888cc83b 100644 --- a/src/cryptenroll/cryptenroll-password.c +++ b/src/cryptenroll/cryptenroll-password.c @@ -62,6 +62,7 @@ int load_volume_key_password( .keyring = "cryptenroll", .credential = "cryptenroll.passphrase", .until = USEC_INFINITY, + .hup_fd = -EBADF, }; for (;;) { @@ -138,6 +139,7 @@ int enroll_password( .keyring = "cryptenroll", .credential = "cryptenroll.new-passphrase", .until = USEC_INFINITY, + .hup_fd = -EBADF, }; for (;;) { diff --git a/src/cryptenroll/cryptenroll-tpm2.c b/src/cryptenroll/cryptenroll-tpm2.c index 42d5a9cd03..fd03fecc62 100644 --- a/src/cryptenroll/cryptenroll-tpm2.c +++ b/src/cryptenroll/cryptenroll-tpm2.c @@ -125,6 +125,7 @@ static int get_pin(char **ret_pin_str, TPM2Flags *ret_flags) { .keyring = "tpm2-pin", .credential = "cryptenroll.new-tpm2-pin", .until = USEC_INFINITY, + .hup_fd = -EBADF, }; pin = strv_free_erase(pin); diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index cb3b591186..e5f21bbce7 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -913,6 +913,7 @@ static int get_password( .keyring = "cryptsetup", .credential = "cryptsetup.passphrase", .until = until, + .hup_fd = -EBADF, }; if (ignore_cached) @@ -1430,6 +1431,7 @@ static int crypt_activate_by_token_pin_ask_password( .keyring = keyring, .credential = credential, .until = until, + .hup_fd = -EBADF, }; r = ask_password_auto(&req, flags, &pins); diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 5658255358..15abb53be8 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -738,6 +738,7 @@ static int prompt_root_password(int rfd) { .tty_fd = -EBADF, .message = msg1, .until = USEC_INFINITY, + .hup_fd = -EBADF, }; r = ask_password_tty(&req, /* flags= */ 0, &a); diff --git a/src/home/homectl.c b/src/home/homectl.c index 611fb966fe..104c35454b 100644 --- a/src/home/homectl.c +++ b/src/home/homectl.c @@ -269,6 +269,7 @@ static int acquire_existing_password( .keyring = "home-password", .credential = "home.password", .until = USEC_INFINITY, + .hup_fd = -EBADF, }; r = ask_password_auto(&req, flags, &password); @@ -329,6 +330,7 @@ static int acquire_recovery_key( .keyring = "home-recovery-key", .credential = "home.recovery-key", .until = USEC_INFINITY, + .hup_fd = -EBADF, }; r = ask_password_auto(&req, flags, &recovery_key); @@ -385,6 +387,7 @@ static int acquire_token_pin( .keyring = "token-pin", .credential = "home.token-pin", .until = USEC_INFINITY, + .hup_fd = -EBADF, }; r = ask_password_auto(&req, flags, &pin); @@ -1241,6 +1244,7 @@ static int acquire_new_password( .keyring = "home-password", .credential = "home.new-password", .until = USEC_INFINITY, + .hup_fd = -EBADF, }; r = ask_password_auto( diff --git a/src/keyutil/keyutil.c b/src/keyutil/keyutil.c index bae7421572..23459e48f5 100644 --- a/src/keyutil/keyutil.c +++ b/src/keyutil/keyutil.c @@ -187,6 +187,7 @@ static int verb_validate(int argc, char *argv[], void *userdata) { .keyring = arg_private_key, .credential = "keyutil.private-key-pin", .until = USEC_INFINITY, + .hup_fd = -EBADF, }, &private_key, &ui); @@ -245,6 +246,7 @@ static int verb_public(int argc, char *argv[], void *userdata) { .keyring = arg_private_key, .credential = "keyutil.private-key-pin", .until = USEC_INFINITY, + .hup_fd = -EBADF, }, &private_key, &ui); diff --git a/src/measure/measure.c b/src/measure/measure.c index fbd039da79..18461797b7 100644 --- a/src/measure/measure.c +++ b/src/measure/measure.c @@ -893,6 +893,7 @@ static int verb_sign(int argc, char *argv[], void *userdata) { .keyring = arg_private_key, .credential = "measure.private-key-pin", .until = USEC_INFINITY, + .hup_fd = -EBADF, }, &privkey, &ui); diff --git a/src/pcrlock/pcrlock.c b/src/pcrlock/pcrlock.c index b22ee57788..72b13f8fac 100644 --- a/src/pcrlock/pcrlock.c +++ b/src/pcrlock/pcrlock.c @@ -4556,6 +4556,7 @@ static int make_policy(bool force, RecoveryPinMode recovery_pin_mode) { .id = "pcrlock-recovery-pin", .credential = "pcrlock.recovery-pin", .until = USEC_INFINITY, + .hup_fd = -EBADF, }; r = ask_password_auto( diff --git a/src/repart/repart.c b/src/repart/repart.c index b381d4808a..7934a97435 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -8577,6 +8577,7 @@ static int parse_argv(int argc, char *argv[], X509 **ret_certificate, EVP_PKEY * .keyring = arg_private_key, .credential = "repart.private-key-pin", .until = USEC_INFINITY, + .hup_fd = -EBADF, }, &private_key, &ui); diff --git a/src/sbsign/sbsign.c b/src/sbsign/sbsign.c index 5c5c884c98..92b8284219 100644 --- a/src/sbsign/sbsign.c +++ b/src/sbsign/sbsign.c @@ -208,6 +208,7 @@ static int verb_sign(int argc, char *argv[], void *userdata) { .keyring = arg_private_key, .credential = "sbsign.private-key-pin", .until = USEC_INFINITY, + .hup_fd = -EBADF, }, &private_key, &ui); diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index 39e6277b37..502b22ee89 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -355,15 +355,30 @@ int ask_password_plymouth( enum { POLL_SOCKET, - POLL_INOTIFY, /* Must be last, because optional */ + POLL_TWO, + POLL_THREE, _POLL_MAX, }; struct pollfd pollfd[_POLL_MAX] = { - [POLL_SOCKET] = { .fd = fd, .events = POLLIN }, - [POLL_INOTIFY] = { .fd = inotify_fd, .events = POLLIN }, + [POLL_SOCKET] = { + .fd = fd, + .events = POLLIN, + }, }; - size_t n_pollfd = inotify_fd >= 0 ? _POLL_MAX : _POLL_MAX-1; + size_t n_pollfd = POLL_SOCKET + 1, inotify_idx = SIZE_MAX, hup_fd_idx = SIZE_MAX; + if (inotify_fd >= 0) + pollfd[inotify_idx = n_pollfd++] = (struct pollfd) { + .fd = inotify_fd, + .events = POLLIN, + }; + if (req->hup_fd >= 0) + pollfd[hup_fd_idx = n_pollfd++] = (struct pollfd) { + .fd = req->hup_fd, + .events = POLLHUP, + }; + + assert(n_pollfd <= _POLL_MAX); for (;;) { usec_t timeout; @@ -384,7 +399,10 @@ int ask_password_plymouth( if (r == 0) return -ETIME; - if (inotify_fd >= 0 && pollfd[POLL_INOTIFY].revents != 0) + if (req->hup_fd >= 0 && pollfd[hup_fd_idx].revents & POLLHUP) + return -ECONNRESET; + + if (inotify_fd >= 0 && pollfd[inotify_idx].revents != 0) (void) flush_fd(inotify_fd); if (pollfd[POLL_SOCKET].revents == 0) @@ -567,15 +585,31 @@ int ask_password_tty( enum { POLL_TTY, - POLL_INOTIFY, /* Must be last, because optional */ + POLL_TWO, + POLL_THREE, _POLL_MAX, }; struct pollfd pollfd[_POLL_MAX] = { - [POLL_TTY] = { .fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO, .events = POLLIN }, - [POLL_INOTIFY] = { .fd = inotify_fd, .events = POLLIN }, + [POLL_TTY] = { + .fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO, + .events = POLLIN, + }, }; - size_t n_pollfd = inotify_fd >= 0 ? _POLL_MAX : _POLL_MAX-1; + size_t n_pollfd = POLL_TTY + 1, inotify_idx = SIZE_MAX, hup_fd_idx = SIZE_MAX; + + if (inotify_fd >= 0) + pollfd[inotify_idx = n_pollfd++] = (struct pollfd) { + .fd = inotify_fd, + .events = POLLIN, + }; + if (req->hup_fd >= 0) + pollfd[hup_fd_idx = n_pollfd++] = (struct pollfd) { + .fd = req->hup_fd, + .events = POLLHUP, + }; + + assert(n_pollfd <= _POLL_MAX); for (;;) { _cleanup_(erase_char) char c; @@ -603,7 +637,12 @@ int ask_password_tty( goto finish; } - if (inotify_fd >= 0 && pollfd[POLL_INOTIFY].revents != 0 && keyring) { + if (req->hup_fd >= 0 && pollfd[hup_fd_idx].revents & POLLHUP) { + r = -ECONNRESET; + goto finish; + } + + if (inotify_fd >= 0 && pollfd[inotify_idx].revents != 0 && keyring) { (void) flush_fd(inotify_fd); r = ask_password_keyring(req, flags, ret); @@ -924,16 +963,29 @@ int ask_password_agent( enum { POLL_SOCKET, POLL_SIGNAL, - POLL_INOTIFY, /* Must be last, because optional */ + POLL_THREE, + POLL_FOUR, _POLL_MAX }; struct pollfd pollfd[_POLL_MAX] = { [POLL_SOCKET] = { .fd = socket_fd, .events = POLLIN }, [POLL_SIGNAL] = { .fd = signal_fd, .events = POLLIN }, - [POLL_INOTIFY] = { .fd = inotify_fd, .events = POLLIN }, }; - size_t n_pollfd = inotify_fd >= 0 ? _POLL_MAX : _POLL_MAX - 1; + size_t n_pollfd = POLL_SIGNAL + 1, inotify_idx = SIZE_MAX, hup_fd_idx = SIZE_MAX; + + if (inotify_fd >= 0) + pollfd[inotify_idx = n_pollfd++] = (struct pollfd) { + .fd = inotify_fd, + .events = POLLIN, + }; + if (req->hup_fd >= 0) + pollfd[hup_fd_idx = n_pollfd ++] = (struct pollfd) { + .fd = req->hup_fd, + .events = POLLHUP, + }; + + assert(n_pollfd <= _POLL_MAX); for (;;) { CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control; @@ -963,7 +1015,10 @@ int ask_password_agent( goto finish; } - if (inotify_fd >= 0 && pollfd[POLL_INOTIFY].revents != 0) { + if (req->hup_fd >= 0 && pollfd[hup_fd_idx].revents & POLLHUP) + return -ECONNRESET; + + if (inotify_fd >= 0 && pollfd[inotify_idx].revents != 0) { (void) flush_fd(inotify_fd); if (req && req->keyring) { diff --git a/src/shared/ask-password-api.h b/src/shared/ask-password-api.h index fe453522fc..03c6d1abdb 100644 --- a/src/shared/ask-password-api.h +++ b/src/shared/ask-password-api.h @@ -28,6 +28,7 @@ typedef struct AskPasswordRequest { const char *credential; /* $CREDENTIALS_DIRECTORY credential name */ const char *flag_file; /* Once this flag file disappears abort the query */ int tty_fd; /* If querying on a TTY, the TTY to query on (or -EBADF) */ + int hup_fd; /* An extra fd to watch for POLLHUP, in which case to abort the query */ usec_t until; /* CLOCK_MONOTONIC time until which to show the prompt (if zero: forever) */ } AskPasswordRequest; diff --git a/src/shared/cryptsetup-fido2.c b/src/shared/cryptsetup-fido2.c index 070908d525..8d4c179183 100644 --- a/src/shared/cryptsetup-fido2.c +++ b/src/shared/cryptsetup-fido2.c @@ -118,6 +118,7 @@ int acquire_fido2_key( .keyring = "fido2-pin", .credential = "cryptsetup.fido2-pin", .until = until, + .hup_fd = -EBADF, }; pins = strv_free_erase(pins); diff --git a/src/shared/cryptsetup-tpm2.c b/src/shared/cryptsetup-tpm2.c index 7a1275eb38..c1cd67bacd 100644 --- a/src/shared/cryptsetup-tpm2.c +++ b/src/shared/cryptsetup-tpm2.c @@ -41,6 +41,7 @@ static int get_pin( .keyring = "tpm2-pin", .credential = askpw_credential, .until = until, + .hup_fd = -EBADF, }; pin = strv_free_erase(pin); diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 3feda770af..86a549477c 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -3083,6 +3083,7 @@ int dissected_image_decrypt_interactively( .keyring = "dissect", .credential = "dissect.passphrase", .until = USEC_INFINITY, + .hup_fd = -EBADF, }; r = ask_password_auto(&req, /* flags= */ 0, &z); diff --git a/src/shared/libfido2-util.c b/src/shared/libfido2-util.c index 200068dce4..101641e7fe 100644 --- a/src/shared/libfido2-util.c +++ b/src/shared/libfido2-util.c @@ -863,6 +863,7 @@ int fido2_generate_hmac_hash( .keyring = "fido2-pin", .credential = askpw_credential, .until = USEC_INFINITY, + .hup_fd = -EBADF, }; r = ask_password_auto(&req, /* flags= */ 0, &pin); diff --git a/src/shared/pkcs11-util.c b/src/shared/pkcs11-util.c index 8d14b2f8f7..a38a91279d 100644 --- a/src/shared/pkcs11-util.c +++ b/src/shared/pkcs11-util.c @@ -387,6 +387,7 @@ int pkcs11_token_login( .keyring = askpw_keyring, .credential = askpw_credential, .until = until, + .hup_fd = -EBADF, }; /* We never cache PINs, simply because it's fatal if we use wrong PINs, since usually there are only 3 tries */ diff --git a/src/test/test-ask-password-api.c b/src/test/test-ask-password-api.c index 38afe0c6ef..d79c476489 100644 --- a/src/test/test-ask-password-api.c +++ b/src/test/test-ask-password-api.c @@ -13,6 +13,7 @@ TEST(ask_password) { .message = "hello?", .keyring = "da key", .until = USEC_INFINITY, + .hup_fd = -EBADF, }; r = ask_password_tty(&req, /* flags= */ ASK_PASSWORD_CONSOLE_COLOR, &ret); diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c index 31292d5acf..094810dcb3 100644 --- a/src/tty-ask-password-agent/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent/tty-ask-password-agent.c @@ -152,6 +152,7 @@ static int agent_ask_password_tty( .message = message, .flag_file = flag_file, .until = until, + .hup_fd = -EBADF, }; r = ask_password_tty(&req, flags, ret); @@ -260,6 +261,7 @@ static int process_one_password_file(const char *filename, FILE *f) { .message = message, .flag_file = filename, .until = not_after, + .hup_fd = -EBADF, }; r = ask_password_plymouth(&req, flags, &passwords);