1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <linux/fscrypt.h>
4 #include <openssl/evp.h>
5 #include <openssl/sha.h>
12 #include "alloc-util.h"
13 #include "errno-util.h"
15 #include "format-util.h"
16 #include "hexdecoct.h"
17 #include "homework-fscrypt.h"
18 #include "homework-mount.h"
19 #include "homework-password-cache.h"
20 #include "homework-quota.h"
22 #include "keyring-util.h"
24 #include "memory-util.h"
25 #include "missing_keyctl.h"
26 #include "missing_syscall.h"
28 #include "mount-util.h"
29 #include "nulstr-util.h"
30 #include "openssl-util.h"
31 #include "parse-util.h"
32 #include "process-util.h"
33 #include "random-util.h"
35 #include "stdio-util.h"
36 #include "string-util.h"
38 #include "tmpfile-util.h"
39 #include "user-record-util.h"
40 #include "user-record.h"
41 #include "user-util.h"
42 #include "xattr-util.h"
44 static int fscrypt_unlink_key(UserRecord
*h
) {
45 _cleanup_free_
void *keyring
= NULL
;
46 size_t keyring_size
= 0, n_keys
= 0;
50 assert(user_record_storage(h
) == USER_FSCRYPT
);
52 r
= fully_set_uid_gid(
55 /* supplementary_gids= */ NULL
,
56 /* n_supplementary_gids= */ 0);
58 return log_error_errno(r
, "Failed to change UID/GID to " UID_FMT
"/" GID_FMT
": %m",
59 h
->uid
, user_record_gid(h
));
61 r
= keyring_read(KEY_SPEC_USER_KEYRING
, &keyring
, &keyring_size
);
63 return log_error_errno(r
, "Failed to read the keyring of user " UID_FMT
": %m", h
->uid
);
65 n_keys
= keyring_size
/ sizeof(key_serial_t
);
66 assert(keyring_size
% sizeof(key_serial_t
) == 0);
68 /* Find any key with a description starting with 'fscrypt:' and unlink it. We need to iterate as we
69 * store the key with a description that uses the hash of the secret key, that we do not have when
70 * we are deactivating. */
71 FOREACH_ARRAY(key
, ((key_serial_t
*) keyring
), n_keys
) {
72 _cleanup_free_
char *description
= NULL
;
75 r
= keyring_describe(*key
, &description
);
77 if (r
== -ENOKEY
) /* Something else deleted it already, that's ok. */
80 return log_error_errno(r
, "Failed to describe key id %d: %m", *key
);
83 /* The description is the final element as per manpage. */
84 d
= strrchr(description
, ';');
86 return log_error_errno(
87 SYNTHETIC_ERRNO(EINVAL
),
88 "Failed to parse description of key id %d: %s",
92 if (!startswith(d
+ 1, "fscrypt:"))
95 r
= keyctl(KEYCTL_UNLINK
, *key
, KEY_SPEC_USER_KEYRING
, 0, 0);
97 if (errno
== ENOKEY
) /* Something else deleted it already, that's ok. */
100 return log_error_errno(
102 "Failed to delete encryption key with id '%d' from the keyring of user " UID_FMT
": %m",
107 log_debug("Deleted encryption key with id '%d' from the keyring of user " UID_FMT
".", *key
, h
->uid
);
113 int home_flush_keyring_fscrypt(UserRecord
*h
) {
117 assert(user_record_storage(h
) == USER_FSCRYPT
);
119 if (!uid_is_valid(h
->uid
))
122 r
= safe_fork("(sd-delkey)",
123 FORK_RESET_SIGNALS
|FORK_CLOSE_ALL_FDS
|FORK_DEATHSIG_SIGTERM
|FORK_LOG
|FORK_WAIT
|FORK_REOPEN_LOG
,
128 if (fscrypt_unlink_key(h
) < 0)
136 static int fscrypt_upload_volume_key(
137 const uint8_t key_descriptor
[static FS_KEY_DESCRIPTOR_SIZE
],
138 const void *volume_key
,
139 size_t volume_key_size
,
140 key_serial_t where
) {
142 _cleanup_free_
char *hex
= NULL
;
143 const char *description
;
144 struct fscrypt_key key
;
147 assert(key_descriptor
);
149 assert(volume_key_size
> 0);
151 if (volume_key_size
> sizeof(key
.raw
))
152 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Volume key too long.");
154 hex
= hexmem(key_descriptor
, FS_KEY_DESCRIPTOR_SIZE
);
158 description
= strjoina("fscrypt:", hex
);
160 key
= (struct fscrypt_key
) {
161 .size
= volume_key_size
,
163 memcpy(key
.raw
, volume_key
, volume_key_size
);
167 /* Upload to the kernel */
168 serial
= add_key("logon", description
, &key
, sizeof(key
), where
);
170 return log_error_errno(errno
, "Failed to install master key in keyring: %m");
172 log_info("Uploaded encryption key to kernel.");
177 static void calculate_key_descriptor(
180 uint8_t ret_key_descriptor
[static FS_KEY_DESCRIPTOR_SIZE
]) {
182 uint8_t hashed
[512 / 8] = {}, hashed2
[512 / 8] = {};
184 /* Derive the key descriptor from the volume key via double SHA512, in order to be compatible with e4crypt */
186 assert_se(SHA512(key
, key_size
, hashed
) == hashed
);
187 assert_se(SHA512(hashed
, sizeof(hashed
), hashed2
) == hashed2
);
189 assert_cc(sizeof(hashed2
) >= FS_KEY_DESCRIPTOR_SIZE
);
191 memcpy(ret_key_descriptor
, hashed2
, FS_KEY_DESCRIPTOR_SIZE
);
194 static int fscrypt_slot_try_one(
195 const char *password
,
196 const void *salt
, size_t salt_size
,
197 const void *encrypted
, size_t encrypted_size
,
198 const uint8_t match_key_descriptor
[static FS_KEY_DESCRIPTOR_SIZE
],
199 void **ret_decrypted
, size_t *ret_decrypted_size
) {
201 _cleanup_(EVP_CIPHER_CTX_freep
) EVP_CIPHER_CTX
*context
= NULL
;
202 _cleanup_(erase_and_freep
) void *decrypted
= NULL
;
203 uint8_t key_descriptor
[FS_KEY_DESCRIPTOR_SIZE
];
204 int decrypted_size_out1
, decrypted_size_out2
;
205 uint8_t derived
[512 / 8] = {};
206 size_t decrypted_size
;
207 const EVP_CIPHER
*cc
;
212 assert(salt_size
> 0);
214 assert(encrypted_size
> 0);
215 assert(match_key_descriptor
);
217 /* Our construction is like this:
219 * 1. In each key slot we store a salt value plus the encrypted volume key
221 * 2. Unlocking is via calculating PBKDF2-HMAC-SHA512 of the supplied password (in combination with
222 * the salt), then using the first 256 bit of the hash as key for decrypting the encrypted
223 * volume key in AES256 counter mode.
225 * 3. Writing a password is similar: calculate PBKDF2-HMAC-SHA512 of the supplied password (in
226 * combination with the salt), then encrypt the volume key in AES256 counter mode with the
230 CLEANUP_ERASE(derived
);
232 if (PKCS5_PBKDF2_HMAC(
233 password
, strlen(password
),
235 0xFFFF, EVP_sha512(),
236 sizeof(derived
), derived
) != 1)
237 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
), "PBKDF2 failed.");
239 context
= EVP_CIPHER_CTX_new();
243 /* We use AES256 in counter mode */
244 assert_se(cc
= EVP_aes_256_ctr());
246 /* We only use the first half of the derived key */
247 assert(sizeof(derived
) >= (size_t) EVP_CIPHER_key_length(cc
));
249 if (EVP_DecryptInit_ex(context
, cc
, NULL
, derived
, NULL
) != 1)
250 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to initialize decryption context.");
252 decrypted_size
= encrypted_size
+ EVP_CIPHER_key_length(cc
) * 2;
253 decrypted
= malloc(decrypted_size
);
257 if (EVP_DecryptUpdate(context
, (uint8_t*) decrypted
, &decrypted_size_out1
, encrypted
, encrypted_size
) != 1)
258 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to decrypt volume key.");
260 assert((size_t) decrypted_size_out1
<= decrypted_size
);
262 if (EVP_DecryptFinal_ex(context
, (uint8_t*) decrypted_size
+ decrypted_size_out1
, &decrypted_size_out2
) != 1)
263 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to finish decryption of volume key.");
265 assert((size_t) decrypted_size_out1
+ (size_t) decrypted_size_out2
< decrypted_size
);
266 decrypted_size
= (size_t) decrypted_size_out1
+ (size_t) decrypted_size_out2
;
268 calculate_key_descriptor(decrypted
, decrypted_size
, key_descriptor
);
270 if (memcmp(key_descriptor
, match_key_descriptor
, FS_KEY_DESCRIPTOR_SIZE
) != 0)
271 return -ENOANO
; /* don't log here */
273 r
= fscrypt_upload_volume_key(key_descriptor
, decrypted
, decrypted_size
, KEY_SPEC_THREAD_KEYRING
);
278 *ret_decrypted
= TAKE_PTR(decrypted
);
279 if (ret_decrypted_size
)
280 *ret_decrypted_size
= decrypted_size
;
285 static int fscrypt_slot_try_many(
287 const void *salt
, size_t salt_size
,
288 const void *encrypted
, size_t encrypted_size
,
289 const uint8_t match_key_descriptor
[static FS_KEY_DESCRIPTOR_SIZE
],
290 void **ret_decrypted
, size_t *ret_decrypted_size
) {
294 STRV_FOREACH(i
, passwords
) {
295 r
= fscrypt_slot_try_one(*i
, salt
, salt_size
, encrypted
, encrypted_size
, match_key_descriptor
, ret_decrypted
, ret_decrypted_size
);
303 static int fscrypt_setup(
304 const PasswordCache
*cache
,
307 void **ret_volume_key
,
308 size_t *ret_volume_key_size
) {
310 _cleanup_free_
char *xattr_buf
= NULL
;
314 assert(setup
->root_fd
>= 0);
316 r
= flistxattr_malloc(setup
->root_fd
, &xattr_buf
);
318 return log_error_errno(r
, "Failed to retrieve xattr list: %m");
320 NULSTR_FOREACH(xa
, xattr_buf
) {
321 _cleanup_free_
void *salt
= NULL
, *encrypted
= NULL
;
322 _cleanup_free_
char *value
= NULL
;
323 size_t salt_size
, encrypted_size
, vsize
;
326 /* Check if this xattr has the format 'trusted.fscrypt_slot<nr>' where '<nr>' is a 32-bit unsigned integer */
327 nr
= startswith(xa
, "trusted.fscrypt_slot");
330 if (safe_atou32(nr
, NULL
) < 0)
333 r
= fgetxattr_malloc(setup
->root_fd
, xa
, &value
, &vsize
);
334 if (r
== -ENODATA
) /* deleted by now? */
337 return log_error_errno(r
, "Failed to read %s xattr: %m", xa
);
339 e
= memchr(value
, ':', vsize
);
341 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "xattr %s lacks ':' separator.", xa
);
343 r
= unbase64mem_full(value
, e
- value
, /* secure = */ false, &salt
, &salt_size
);
345 return log_error_errno(r
, "Failed to decode salt of %s: %m", xa
);
347 r
= unbase64mem_full(e
+ 1, vsize
- (e
- value
) - 1, /* secure = */ false, &encrypted
, &encrypted_size
);
349 return log_error_errno(r
, "Failed to decode encrypted key of %s: %m", xa
);
353 FOREACH_ARGUMENT(list
, cache
->pkcs11_passwords
, cache
->fido2_passwords
, password
) {
354 r
= fscrypt_slot_try_many(
357 encrypted
, encrypted_size
,
358 setup
->fscrypt_key_descriptor
,
359 ret_volume_key
, ret_volume_key_size
);
367 return log_error_errno(SYNTHETIC_ERRNO(ENOKEY
), "Failed to set up home directory with provided passwords.");
370 int home_setup_fscrypt(
373 const PasswordCache
*cache
) {
375 _cleanup_(erase_and_freep
) void *volume_key
= NULL
;
376 struct fscrypt_policy policy
= {};
377 size_t volume_key_size
= 0;
382 assert(user_record_storage(h
) == USER_FSCRYPT
);
384 assert(setup
->root_fd
< 0);
386 assert_se(ip
= user_record_image_path(h
));
388 setup
->root_fd
= open(ip
, O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
389 if (setup
->root_fd
< 0)
390 return log_error_errno(errno
, "Failed to open home directory: %m");
392 if (ioctl(setup
->root_fd
, FS_IOC_GET_ENCRYPTION_POLICY
, &policy
) < 0) {
393 if (errno
== ENODATA
)
394 return log_error_errno(errno
, "Home directory %s is not encrypted.", ip
);
395 if (ERRNO_IS_NOT_SUPPORTED(errno
)) {
396 log_error_errno(errno
, "File system does not support fscrypt: %m");
397 return -ENOLINK
; /* make recognizable */
399 return log_error_errno(errno
, "Failed to acquire encryption policy of %s: %m", ip
);
402 memcpy(setup
->fscrypt_key_descriptor
, policy
.master_key_descriptor
, FS_KEY_DESCRIPTOR_SIZE
);
413 /* Also install the access key in the user's own keyring */
415 if (uid_is_valid(h
->uid
)) {
416 r
= safe_fork("(sd-addkey)",
417 FORK_RESET_SIGNALS
|FORK_CLOSE_ALL_FDS
|FORK_DEATHSIG_SIGTERM
|FORK_LOG
|FORK_WAIT
|FORK_REOPEN_LOG
,
420 return log_error_errno(r
, "Failed install encryption key in user's keyring: %m");
424 r
= fully_set_uid_gid(h
->uid
, user_record_gid(h
), /* supplementary_gids= */ NULL
, /* n_supplementary_gids= */ 0);
426 log_error_errno(r
, "Failed to change UID/GID to " UID_FMT
"/" GID_FMT
": %m", h
->uid
, user_record_gid(h
));
430 r
= fscrypt_upload_volume_key(
431 setup
->fscrypt_key_descriptor
,
434 KEY_SPEC_USER_KEYRING
);
442 /* We'll bind mount the image directory to a new mount point where we'll start adjusting it. Only
443 * once that's complete we'll move the thing to its final place eventually. */
444 r
= home_unshare_and_mkdir();
448 r
= mount_follow_verbose(LOG_ERR
, ip
, HOME_RUNTIME_WORK_DIR
, NULL
, MS_BIND
, NULL
);
452 setup
->undo_mount
= true;
454 /* Turn off any form of propagation for this */
455 r
= mount_nofollow_verbose(LOG_ERR
, NULL
, HOME_RUNTIME_WORK_DIR
, NULL
, MS_PRIVATE
, NULL
);
459 /* Adjust MS_SUID and similar flags */
460 r
= mount_nofollow_verbose(LOG_ERR
, NULL
, HOME_RUNTIME_WORK_DIR
, NULL
, MS_BIND
|MS_REMOUNT
|user_record_mount_flags(h
), NULL
);
464 safe_close(setup
->root_fd
);
465 setup
->root_fd
= open(HOME_RUNTIME_WORK_DIR
, O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
466 if (setup
->root_fd
< 0)
467 return log_error_errno(errno
, "Failed to open home directory: %m");
472 static int fscrypt_slot_set(
474 const void *volume_key
,
475 size_t volume_key_size
,
476 const char *password
,
479 _cleanup_free_
char *salt_base64
= NULL
, *encrypted_base64
= NULL
, *joined
= NULL
;
480 char label
[STRLEN("trusted.fscrypt_slot") + DECIMAL_STR_MAX(nr
) + 1];
481 _cleanup_(EVP_CIPHER_CTX_freep
) EVP_CIPHER_CTX
*context
= NULL
;
482 int r
, encrypted_size_out1
, encrypted_size_out2
;
483 uint8_t salt
[64], derived
[512 / 8] = {};
484 _cleanup_free_
void *encrypted
= NULL
;
485 const EVP_CIPHER
*cc
;
486 size_t encrypted_size
;
489 r
= crypto_random_bytes(salt
, sizeof(salt
));
491 return log_error_errno(r
, "Failed to generate salt: %m");
493 CLEANUP_ERASE(derived
);
495 if (PKCS5_PBKDF2_HMAC(
496 password
, strlen(password
),
498 0xFFFF, EVP_sha512(),
499 sizeof(derived
), derived
) != 1)
500 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
), "PBKDF2 failed");
502 context
= EVP_CIPHER_CTX_new();
506 /* We use AES256 in counter mode */
507 cc
= EVP_aes_256_ctr();
509 /* We only use the first half of the derived key */
510 assert(sizeof(derived
) >= (size_t) EVP_CIPHER_key_length(cc
));
512 if (EVP_EncryptInit_ex(context
, cc
, NULL
, derived
, NULL
) != 1)
513 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to initialize encryption context.");
515 encrypted_size
= volume_key_size
+ EVP_CIPHER_key_length(cc
) * 2;
516 encrypted
= malloc(encrypted_size
);
520 if (EVP_EncryptUpdate(context
, (uint8_t*) encrypted
, &encrypted_size_out1
, volume_key
, volume_key_size
) != 1)
521 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to encrypt volume key.");
523 assert((size_t) encrypted_size_out1
<= encrypted_size
);
525 if (EVP_EncryptFinal_ex(context
, (uint8_t*) encrypted_size
+ encrypted_size_out1
, &encrypted_size_out2
) != 1)
526 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to finish encryption of volume key.");
528 assert((size_t) encrypted_size_out1
+ (size_t) encrypted_size_out2
< encrypted_size
);
529 encrypted_size
= (size_t) encrypted_size_out1
+ (size_t) encrypted_size_out2
;
531 ss
= base64mem(salt
, sizeof(salt
), &salt_base64
);
535 ss
= base64mem(encrypted
, encrypted_size
, &encrypted_base64
);
539 joined
= strjoin(salt_base64
, ":", encrypted_base64
);
543 xsprintf(label
, "trusted.fscrypt_slot%" PRIu32
, nr
);
544 if (fsetxattr(root_fd
, label
, joined
, strlen(joined
), 0) < 0)
545 return log_error_errno(errno
, "Failed to write xattr %s: %m", label
);
547 log_info("Written key slot %s.", label
);
552 int home_create_fscrypt(
555 char **effective_passwords
,
556 UserRecord
**ret_home
) {
558 _cleanup_(rm_rf_physical_and_freep
) char *temporary
= NULL
;
559 _cleanup_(user_record_unrefp
) UserRecord
*new_home
= NULL
;
560 _cleanup_(erase_and_freep
) void *volume_key
= NULL
;
561 _cleanup_close_
int mount_fd
= -EBADF
;
562 struct fscrypt_policy policy
= {};
563 size_t volume_key_size
= 512 / 8;
564 _cleanup_free_
char *d
= NULL
;
570 assert(user_record_storage(h
) == USER_FSCRYPT
);
574 assert_se(ip
= user_record_image_path(h
));
576 r
= tempfn_random(ip
, "homework", &d
);
578 return log_error_errno(r
, "Failed to allocate temporary directory: %m");
580 (void) mkdir_parents(d
, 0755);
582 if (mkdir(d
, 0700) < 0)
583 return log_error_errno(errno
, "Failed to create temporary home directory %s: %m", d
);
585 temporary
= TAKE_PTR(d
); /* Needs to be destroyed now */
587 r
= home_unshare_and_mkdir();
591 setup
->root_fd
= open(temporary
, O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
592 if (setup
->root_fd
< 0)
593 return log_error_errno(errno
, "Failed to open temporary home directory: %m");
595 if (ioctl(setup
->root_fd
, FS_IOC_GET_ENCRYPTION_POLICY
, &policy
) < 0) {
596 if (ERRNO_IS_NOT_SUPPORTED(errno
)) {
597 log_error_errno(errno
, "File system does not support fscrypt: %m");
598 return -ENOLINK
; /* make recognizable */
600 if (errno
!= ENODATA
)
601 return log_error_errno(errno
, "Failed to get fscrypt policy of directory: %m");
603 return log_error_errno(SYNTHETIC_ERRNO(EBUSY
), "Parent of %s already encrypted, refusing.", d
);
605 volume_key
= malloc(volume_key_size
);
609 r
= crypto_random_bytes(volume_key
, volume_key_size
);
611 return log_error_errno(r
, "Failed to acquire volume key: %m");
613 log_info("Generated volume key of size %zu.", volume_key_size
);
615 policy
= (struct fscrypt_policy
) {
616 .contents_encryption_mode
= FS_ENCRYPTION_MODE_AES_256_XTS
,
617 .filenames_encryption_mode
= FS_ENCRYPTION_MODE_AES_256_CTS
,
618 .flags
= FS_POLICY_FLAGS_PAD_32
,
621 calculate_key_descriptor(volume_key
, volume_key_size
, policy
.master_key_descriptor
);
623 r
= fscrypt_upload_volume_key(policy
.master_key_descriptor
, volume_key
, volume_key_size
, KEY_SPEC_THREAD_KEYRING
);
627 log_info("Uploaded volume key to kernel.");
629 if (ioctl(setup
->root_fd
, FS_IOC_SET_ENCRYPTION_POLICY
, &policy
) < 0)
630 return log_error_errno(errno
, "Failed to set fscrypt policy on directory: %m");
632 log_info("Encryption policy set.");
634 STRV_FOREACH(i
, effective_passwords
) {
635 r
= fscrypt_slot_set(setup
->root_fd
, volume_key
, volume_key_size
, *i
, nr
);
642 (void) home_update_quota_classic(h
, setup
->root_fd
, temporary
);
644 r
= home_shift_uid(setup
->root_fd
, HOME_RUNTIME_WORK_DIR
, h
->uid
, h
->uid
, &mount_fd
);
646 setup
->undo_mount
= true; /* If uidmaps worked we have a mount to undo again */
649 /* If we have established a new mount, then we can use that as new root fd to our home directory. */
650 safe_close(setup
->root_fd
);
652 setup
->root_fd
= fd_reopen(mount_fd
, O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
653 if (setup
->root_fd
< 0)
654 return log_error_errno(setup
->root_fd
, "Unable to convert mount fd into proper directory fd: %m");
656 mount_fd
= safe_close(mount_fd
);
659 r
= home_populate(h
, setup
->root_fd
);
663 r
= home_sync_and_statfs(setup
->root_fd
, NULL
);
667 r
= user_record_clone(h
, USER_RECORD_LOAD_MASK_SECRET
|USER_RECORD_PERMISSIVE
, &new_home
);
669 return log_error_errno(r
, "Failed to clone record: %m");
671 r
= user_record_add_binding(
686 return log_error_errno(r
, "Failed to add binding to record: %m");
688 setup
->root_fd
= safe_close(setup
->root_fd
);
690 r
= home_setup_undo_mount(setup
, LOG_ERR
);
694 if (rename(temporary
, ip
) < 0)
695 return log_error_errno(errno
, "Failed to rename %s to %s: %m", temporary
, ip
);
697 temporary
= mfree(temporary
);
699 log_info("Everything completed.");
701 *ret_home
= TAKE_PTR(new_home
);
705 int home_passwd_fscrypt(
708 const PasswordCache
*cache
, /* the passwords acquired via PKCS#11/FIDO2 security tokens */
709 char **effective_passwords
/* new passwords */) {
711 _cleanup_(erase_and_freep
) void *volume_key
= NULL
;
712 _cleanup_free_
char *xattr_buf
= NULL
;
713 size_t volume_key_size
= 0;
718 assert(user_record_storage(h
) == USER_FSCRYPT
);
730 STRV_FOREACH(p
, effective_passwords
) {
731 r
= fscrypt_slot_set(setup
->root_fd
, volume_key
, volume_key_size
, *p
, slot
);
738 r
= flistxattr_malloc(setup
->root_fd
, &xattr_buf
);
740 return log_error_errno(r
, "Failed to retrieve xattr list: %m");
742 NULSTR_FOREACH(xa
, xattr_buf
) {
746 /* Check if this xattr has the format 'trusted.fscrypt_slot<nr>' where '<nr>' is a 32-bit unsigned integer */
747 nr
= startswith(xa
, "trusted.fscrypt_slot");
750 if (safe_atou32(nr
, &z
) < 0)
756 if (fremovexattr(setup
->root_fd
, xa
) < 0)
757 if (errno
!= ENODATA
)
758 log_warning_errno(errno
, "Failed to remove xattr %s: %m", xa
);