summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuca Boccassi <bluca@debian.org>2024-06-06 17:34:20 +0200
committerGitHub <noreply@github.com>2024-06-06 17:34:20 +0200
commitb06ab6b92b21cf572cbfdf650ca7cfc3e9d06e29 (patch)
tree2c890e30eedaf7cdc0b5a932622e63e733b4bb50
parentmkosi: do a sparse checkout of debian/ubuntu packaging repo (diff)
parenthomed: flush fscrypt key on lock/deactivate (diff)
downloadsystemd-b06ab6b92b21cf572cbfdf650ca7cfc3e9d06e29.tar.xz
systemd-b06ab6b92b21cf572cbfdf650ca7cfc3e9d06e29.zip
Merge pull request #33189 from bluca/fscrypt_flush
homed: flush fscrypt key on lock/deactivate
-rw-r--r--src/basic/keyring-util.c (renamed from src/shared/keyring-util.c)31
-rw-r--r--src/basic/keyring-util.h (renamed from src/shared/keyring-util.h)1
-rw-r--r--src/basic/meson.build1
-rw-r--r--src/home/homework-fscrypt.c93
-rw-r--r--src/home/homework-fscrypt.h2
-rw-r--r--src/home/homework.c3
-rw-r--r--src/libsystemd/sd-id128/sd-id128.c23
-rw-r--r--src/shared/meson.build1
8 files changed, 135 insertions, 20 deletions
diff --git a/src/shared/keyring-util.c b/src/basic/keyring-util.c
index fadd90ebcc..c32bd50b6f 100644
--- a/src/shared/keyring-util.c
+++ b/src/basic/keyring-util.c
@@ -33,3 +33,34 @@ int keyring_read(key_serial_t serial, void **ret, size_t *ret_size) {
bufsize = (size_t) n;
}
}
+
+int keyring_describe(key_serial_t serial, char **ret) {
+ _cleanup_free_ char *tuple = NULL;
+ size_t sz = 64;
+ int c = -1; /* Workaround for maybe-uninitialized false positive due to missing_syscall indirection */
+
+ assert(ret);
+
+ for (;;) {
+ tuple = new(char, sz);
+ if (!tuple)
+ return log_oom_debug();
+
+ c = keyctl(KEYCTL_DESCRIBE, serial, (unsigned long) tuple, c, 0);
+ if (c < 0)
+ return log_debug_errno(errno, "Failed to describe key id %d: %m", serial);
+
+ if ((size_t) c <= sz)
+ break;
+
+ sz = c;
+ free(tuple);
+ }
+
+ /* The kernel returns a final NUL in the string, verify that. */
+ assert(tuple[c-1] == 0);
+
+ *ret = TAKE_PTR(tuple);
+
+ return 0;
+}
diff --git a/src/shared/keyring-util.h b/src/basic/keyring-util.h
index c8c53f1be1..6e6e6856ad 100644
--- a/src/shared/keyring-util.h
+++ b/src/basic/keyring-util.h
@@ -9,3 +9,4 @@
#define TAKE_KEY_SERIAL(key_serial) TAKE_GENERIC(key_serial, key_serial_t, -1)
int keyring_read(key_serial_t serial, void **ret, size_t *ret_size);
+int keyring_describe(key_serial_t serial, char **ret);
diff --git a/src/basic/meson.build b/src/basic/meson.build
index d71c9d8bc7..9a214575a5 100644
--- a/src/basic/meson.build
+++ b/src/basic/meson.build
@@ -57,6 +57,7 @@ basic_sources = files(
'lock-util.c',
'log.c',
'login-util.c',
+ 'keyring-util.c',
'memfd-util.c',
'memory-util.c',
'mempool.c',
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();
diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c
index 62b8aaa347..fc1107b4e8 100644
--- a/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/libsystemd/sd-id128/sd-id128.c
@@ -13,6 +13,7 @@
#include "hmac.h"
#include "id128-util.h"
#include "io-util.h"
+#include "keyring-util.h"
#include "macro.h"
#include "missing_syscall.h"
#include "missing_threads.h"
@@ -202,7 +203,6 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
char *d, *p, *g, *u, *e;
unsigned long perms;
key_serial_t key;
- size_t sz = 256;
uid_t uid;
gid_t gid;
int r, c;
@@ -221,24 +221,9 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
return -errno;
}
- for (;;) {
- description = new(char, sz);
- if (!description)
- return -ENOMEM;
-
- c = keyctl(KEYCTL_DESCRIBE, key, (unsigned long) description, sz, 0);
- if (c < 0)
- return -errno;
-
- if ((size_t) c <= sz)
- break;
-
- sz = c;
- free(description);
- }
-
- /* The kernel returns a final NUL in the string, verify that. */
- assert(description[c-1] == 0);
+ r = keyring_describe(key, &description);
+ if (r < 0)
+ return r;
/* Chop off the final description string */
d = strrchr(description, ';');
diff --git a/src/shared/meson.build b/src/shared/meson.build
index 8fb2b7ec7f..c5106d87d5 100644
--- a/src/shared/meson.build
+++ b/src/shared/meson.build
@@ -100,7 +100,6 @@ shared_sources = files(
'kbd-util.c',
'kernel-config.c',
'kernel-image.c',
- 'keyring-util.c',
'killall.c',
'label-util.c',
'libarchive-util.c',