Skip to content

Commit b06ab6b

Browse files
authored
Merge pull request #33189 from bluca/fscrypt_flush
homed: flush fscrypt key on lock/deactivate
2 parents b99dc98 + c4b5de7 commit b06ab6b

File tree

8 files changed

+135
-20
lines changed

8 files changed

+135
-20
lines changed

src/shared/keyring-util.c renamed to src/basic/keyring-util.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,34 @@ int keyring_read(key_serial_t serial, void **ret, size_t *ret_size) {
3333
bufsize = (size_t) n;
3434
}
3535
}
36+
37+
int keyring_describe(key_serial_t serial, char **ret) {
38+
_cleanup_free_ char *tuple = NULL;
39+
size_t sz = 64;
40+
int c = -1; /* Workaround for maybe-uninitialized false positive due to missing_syscall indirection */
41+
42+
assert(ret);
43+
44+
for (;;) {
45+
tuple = new(char, sz);
46+
if (!tuple)
47+
return log_oom_debug();
48+
49+
c = keyctl(KEYCTL_DESCRIBE, serial, (unsigned long) tuple, c, 0);
50+
if (c < 0)
51+
return log_debug_errno(errno, "Failed to describe key id %d: %m", serial);
52+
53+
if ((size_t) c <= sz)
54+
break;
55+
56+
sz = c;
57+
free(tuple);
58+
}
59+
60+
/* The kernel returns a final NUL in the string, verify that. */
61+
assert(tuple[c-1] == 0);
62+
63+
*ret = TAKE_PTR(tuple);
64+
65+
return 0;
66+
}

src/shared/keyring-util.h renamed to src/basic/keyring-util.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@
99
#define TAKE_KEY_SERIAL(key_serial) TAKE_GENERIC(key_serial, key_serial_t, -1)
1010

1111
int keyring_read(key_serial_t serial, void **ret, size_t *ret_size);
12+
int keyring_describe(key_serial_t serial, char **ret);

src/basic/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ basic_sources = files(
5757
'lock-util.c',
5858
'log.c',
5959
'login-util.c',
60+
'keyring-util.c',
6061
'memfd-util.c',
6162
'memory-util.c',
6263
'mempool.c',

src/home/homework-fscrypt.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "homework-fscrypt.h"
1313
#include "homework-mount.h"
1414
#include "homework-quota.h"
15+
#include "keyring-util.h"
1516
#include "memory-util.h"
1617
#include "missing_keyctl.h"
1718
#include "missing_syscall.h"
@@ -29,6 +30,98 @@
2930
#include "user-util.h"
3031
#include "xattr-util.h"
3132

33+
static int fscrypt_unlink_key(UserRecord *h) {
34+
_cleanup_free_ void *keyring = NULL;
35+
size_t keyring_size = 0, n_keys = 0;
36+
int r;
37+
38+
assert(h);
39+
assert(user_record_storage(h) == USER_FSCRYPT);
40+
41+
r = fully_set_uid_gid(
42+
h->uid,
43+
user_record_gid(h),
44+
/* supplementary_gids= */ NULL,
45+
/* n_supplementary_gids= */ 0);
46+
if (r < 0)
47+
return log_error_errno(r, "Failed to change UID/GID to " UID_FMT "/" GID_FMT ": %m",
48+
h->uid, user_record_gid(h));
49+
50+
r = keyring_read(KEY_SPEC_USER_KEYRING, &keyring, &keyring_size);
51+
if (r < 0)
52+
return log_error_errno(r, "Failed to read the keyring of user " UID_FMT ": %m", h->uid);
53+
54+
n_keys = keyring_size / sizeof(key_serial_t);
55+
assert(keyring_size % sizeof(key_serial_t) == 0);
56+
57+
/* Find any key with a description starting with 'fscrypt:' and unlink it. We need to iterate as we
58+
* store the key with a description that uses the hash of the secret key, that we do not have when
59+
* we are deactivating. */
60+
FOREACH_ARRAY(key, ((key_serial_t *) keyring), n_keys) {
61+
_cleanup_free_ char *description = NULL;
62+
char *d;
63+
64+
r = keyring_describe(*key, &description);
65+
if (r < 0) {
66+
if (r == -ENOKEY) /* Something else deleted it already, that's ok. */
67+
continue;
68+
69+
return log_error_errno(r, "Failed to describe key id %d: %m", *key);
70+
}
71+
72+
/* The decription is the final element as per manpage. */
73+
d = strrchr(description, ';');
74+
if (!d)
75+
return log_error_errno(
76+
SYNTHETIC_ERRNO(EINVAL),
77+
"Failed to parse description of key id %d: %s",
78+
*key,
79+
description);
80+
81+
if (!startswith(d + 1, "fscrypt:"))
82+
continue;
83+
84+
r = keyctl(KEYCTL_UNLINK, *key, KEY_SPEC_USER_KEYRING, 0, 0);
85+
if (r < 0) {
86+
if (errno == ENOKEY) /* Something else deleted it already, that's ok. */
87+
continue;
88+
89+
return log_error_errno(
90+
errno,
91+
"Failed to delete encryption key with id '%d' from the keyring of user " UID_FMT ": %m",
92+
*key,
93+
h->uid);
94+
}
95+
96+
log_debug("Deleted encryption key with id '%d' from the keyring of user " UID_FMT ".", *key, h->uid);
97+
}
98+
99+
return 0;
100+
}
101+
102+
int home_flush_keyring_fscrypt(UserRecord *h) {
103+
int r;
104+
105+
assert(h);
106+
assert(user_record_storage(h) == USER_FSCRYPT);
107+
108+
if (!uid_is_valid(h->uid))
109+
return 0;
110+
111+
r = safe_fork("(sd-delkey)",
112+
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_WAIT|FORK_REOPEN_LOG,
113+
NULL);
114+
if (r < 0)
115+
return r;
116+
if (r == 0) {
117+
if (fscrypt_unlink_key(h) < 0)
118+
_exit(EXIT_FAILURE);
119+
_exit(EXIT_SUCCESS);
120+
}
121+
122+
return 0;
123+
}
124+
32125
static int fscrypt_upload_volume_key(
33126
const uint8_t key_descriptor[static FS_KEY_DESCRIPTOR_SIZE],
34127
const void *volume_key,

src/home/homework-fscrypt.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ int home_setup_fscrypt(UserRecord *h, HomeSetup *setup, const PasswordCache *cac
99
int home_create_fscrypt(UserRecord *h, HomeSetup *setup, char **effective_passwords, UserRecord **ret_home);
1010

1111
int home_passwd_fscrypt(UserRecord *h, HomeSetup *setup, const PasswordCache *cache, char **effective_passwords);
12+
13+
int home_flush_keyring_fscrypt(UserRecord *h);

src/home/homework.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,9 @@ static int keyring_flush(UserRecord *h) {
379379

380380
assert(h);
381381

382+
if (user_record_storage(h) == USER_FSCRYPT)
383+
(void) home_flush_keyring_fscrypt(h);
384+
382385
name = strjoin("homework-user-", h->user_name);
383386
if (!name)
384387
return log_oom();

src/libsystemd/sd-id128/sd-id128.c

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "hmac.h"
1414
#include "id128-util.h"
1515
#include "io-util.h"
16+
#include "keyring-util.h"
1617
#include "macro.h"
1718
#include "missing_syscall.h"
1819
#include "missing_threads.h"
@@ -202,7 +203,6 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
202203
char *d, *p, *g, *u, *e;
203204
unsigned long perms;
204205
key_serial_t key;
205-
size_t sz = 256;
206206
uid_t uid;
207207
gid_t gid;
208208
int r, c;
@@ -221,24 +221,9 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
221221
return -errno;
222222
}
223223

224-
for (;;) {
225-
description = new(char, sz);
226-
if (!description)
227-
return -ENOMEM;
228-
229-
c = keyctl(KEYCTL_DESCRIBE, key, (unsigned long) description, sz, 0);
230-
if (c < 0)
231-
return -errno;
232-
233-
if ((size_t) c <= sz)
234-
break;
235-
236-
sz = c;
237-
free(description);
238-
}
239-
240-
/* The kernel returns a final NUL in the string, verify that. */
241-
assert(description[c-1] == 0);
224+
r = keyring_describe(key, &description);
225+
if (r < 0)
226+
return r;
242227

243228
/* Chop off the final description string */
244229
d = strrchr(description, ';');

src/shared/meson.build

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ shared_sources = files(
100100
'kbd-util.c',
101101
'kernel-config.c',
102102
'kernel-image.c',
103-
'keyring-util.c',
104103
'killall.c',
105104
'label-util.c',
106105
'libarchive-util.c',

0 commit comments

Comments
 (0)