diff options
author | Luca Boccassi <bluca@debian.org> | 2024-06-04 04:17:42 +0200 |
---|---|---|
committer | Luca Boccassi <bluca@debian.org> | 2024-06-06 14:52:26 +0200 |
commit | c4b5de7eff3d3b51ae88e74fecba09e4fbea4464 (patch) | |
tree | 144926653c009c4f397865e8813b8492341df9ef /src | |
parent | util: add keyring_describe helper and move to basic (diff) | |
download | systemd-c4b5de7eff3d3b51ae88e74fecba09e4fbea4464.tar.xz systemd-c4b5de7eff3d3b51ae88e74fecba09e4fbea4464.zip |
homed: flush fscrypt key on lock/deactivate
The fscrypt key is added to the user keyring, and needs to be flushed out too.
Fixes https://github.com/systemd/systemd/issues/33138
Diffstat (limited to 'src')
-rw-r--r-- | src/home/homework-fscrypt.c | 93 | ||||
-rw-r--r-- | src/home/homework-fscrypt.h | 2 | ||||
-rw-r--r-- | src/home/homework.c | 3 |
3 files changed, 98 insertions, 0 deletions
diff --git a/src/home/homework-fscrypt.c b/src/home/homework-fscrypt.c index 46a7756873..125714ba1e 100644 --- a/src/home/homework-fscrypt.c +++ b/src/home/homework-fscrypt.c @@ -12,6 +12,7 @@ #include "homework-fscrypt.h" #include "homework-mount.h" #include "homework-quota.h" +#include "keyring-util.h" #include "memory-util.h" #include "missing_keyctl.h" #include "missing_syscall.h" @@ -29,6 +30,98 @@ #include "user-util.h" #include "xattr-util.h" +static int fscrypt_unlink_key(UserRecord *h) { + _cleanup_free_ void *keyring = NULL; + size_t keyring_size = 0, n_keys = 0; + int r; + + assert(h); + assert(user_record_storage(h) == USER_FSCRYPT); + + r = fully_set_uid_gid( + h->uid, + user_record_gid(h), + /* supplementary_gids= */ NULL, + /* n_supplementary_gids= */ 0); + if (r < 0) + return log_error_errno(r, "Failed to change UID/GID to " UID_FMT "/" GID_FMT ": %m", + h->uid, user_record_gid(h)); + + r = keyring_read(KEY_SPEC_USER_KEYRING, &keyring, &keyring_size); + if (r < 0) + return log_error_errno(r, "Failed to read the keyring of user " UID_FMT ": %m", h->uid); + + n_keys = keyring_size / sizeof(key_serial_t); + assert(keyring_size % sizeof(key_serial_t) == 0); + + /* Find any key with a description starting with 'fscrypt:' and unlink it. We need to iterate as we + * store the key with a description that uses the hash of the secret key, that we do not have when + * we are deactivating. */ + FOREACH_ARRAY(key, ((key_serial_t *) keyring), n_keys) { + _cleanup_free_ char *description = NULL; + char *d; + + r = keyring_describe(*key, &description); + if (r < 0) { + if (r == -ENOKEY) /* Something else deleted it already, that's ok. */ + continue; + + return log_error_errno(r, "Failed to describe key id %d: %m", *key); + } + + /* The decription is the final element as per manpage. */ + d = strrchr(description, ';'); + if (!d) + return log_error_errno( + SYNTHETIC_ERRNO(EINVAL), + "Failed to parse description of key id %d: %s", + *key, + description); + + if (!startswith(d + 1, "fscrypt:")) + continue; + + r = keyctl(KEYCTL_UNLINK, *key, KEY_SPEC_USER_KEYRING, 0, 0); + if (r < 0) { + if (errno == ENOKEY) /* Something else deleted it already, that's ok. */ + continue; + + return log_error_errno( + errno, + "Failed to delete encryption key with id '%d' from the keyring of user " UID_FMT ": %m", + *key, + h->uid); + } + + log_debug("Deleted encryption key with id '%d' from the keyring of user " UID_FMT ".", *key, h->uid); + } + + return 0; +} + +int home_flush_keyring_fscrypt(UserRecord *h) { + int r; + + assert(h); + assert(user_record_storage(h) == USER_FSCRYPT); + + if (!uid_is_valid(h->uid)) + return 0; + + r = safe_fork("(sd-delkey)", + FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_WAIT|FORK_REOPEN_LOG, + NULL); + if (r < 0) + return r; + if (r == 0) { + if (fscrypt_unlink_key(h) < 0) + _exit(EXIT_FAILURE); + _exit(EXIT_SUCCESS); + } + + return 0; +} + static int fscrypt_upload_volume_key( const uint8_t key_descriptor[static FS_KEY_DESCRIPTOR_SIZE], const void *volume_key, diff --git a/src/home/homework-fscrypt.h b/src/home/homework-fscrypt.h index 7c2d7aace4..289e9d86fb 100644 --- a/src/home/homework-fscrypt.h +++ b/src/home/homework-fscrypt.h @@ -9,3 +9,5 @@ int home_setup_fscrypt(UserRecord *h, HomeSetup *setup, const PasswordCache *cac int home_create_fscrypt(UserRecord *h, HomeSetup *setup, char **effective_passwords, UserRecord **ret_home); int home_passwd_fscrypt(UserRecord *h, HomeSetup *setup, const PasswordCache *cache, char **effective_passwords); + +int home_flush_keyring_fscrypt(UserRecord *h); diff --git a/src/home/homework.c b/src/home/homework.c index b556904651..482db23dbc 100644 --- a/src/home/homework.c +++ b/src/home/homework.c @@ -379,6 +379,9 @@ static int keyring_flush(UserRecord *h) { assert(h); + if (user_record_storage(h) == USER_FSCRYPT) + (void) home_flush_keyring_fscrypt(h); + name = strjoin("homework-user-", h->user_name); if (!name) return log_oom(); |