boot: honour "read-only" vfat flag on random seed file (#43012)
Inspired by #42979
This commit is contained in:
@@ -216,6 +216,13 @@ boot, in order to ensure the entropy pool is filled up quickly.
|
||||
too), which should be safe even with FAT file system drivers built into
|
||||
low-quality EFI firmwares.
|
||||
|
||||
If the random seed file has the read-only FAT file attribute set, or if the
|
||||
ESP file system is read-only as a whole, the seed is neither updated nor
|
||||
used: a seed that cannot be updated would be identical on every boot, and
|
||||
hence must not be credited. Setting the read-only file attribute on
|
||||
`/loader/random-seed` may thus be used to explicitly turn off random seed
|
||||
handling, for example in OS images that are replicated to multiple systems.
|
||||
|
||||
4. A kernel command line option `systemd.random_seed=` may be used to pass in a
|
||||
base64 encoded seed to initialize the kernel's entropy pool from during
|
||||
early service manager initialization.
|
||||
|
||||
@@ -390,7 +390,10 @@
|
||||
<filename>/EFI/Linux/</filename> on the ESP and the Extended Boot Loader partition.</para>
|
||||
|
||||
<para>Optionally, a random seed for early boot entropy pool provisioning is stored in
|
||||
<filename>/loader/random-seed</filename> in the ESP.</para>
|
||||
<filename>/loader/random-seed</filename> in the ESP. If the read-only file attribute is set on this
|
||||
file, it is neither updated nor used: a seed that cannot be updated would be identical on every boot,
|
||||
and hence must not be credited. The file attribute may thus be used to explicitly turn off random seed
|
||||
handling, for example in OS images that are replicated to multiple systems.</para>
|
||||
|
||||
<para>During initialization, <command>systemd-boot</command> automatically loads all driver files placed
|
||||
in the <filename>/EFI/systemd/drivers/</filename> directory of the ESP. The files placed there must have
|
||||
|
||||
@@ -223,7 +223,7 @@ static EFI_STATUS acquire_secret_mixin(
|
||||
(char16_t *) BOOT_SECRET_MIXIN_PATH,
|
||||
EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,
|
||||
/* Attributes= */ 0);
|
||||
if (err == EFI_WRITE_PROTECTED) {
|
||||
if (EFI_STATUS_IS_WRITE_REFUSED(err)) {
|
||||
err = root_dir->Open(
|
||||
root_dir,
|
||||
&handle,
|
||||
@@ -243,8 +243,13 @@ static EFI_STATUS acquire_secret_mixin(
|
||||
err = get_file_info(handle, &info, /* ret_size= */ NULL);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_debug_status(err, "Failed to get boot secret mixin file '%ls' info: %m", BOOT_SECRET_MIXIN_PATH);
|
||||
if (info->FileSize == 0 && writable) /* New file? Fill it. */
|
||||
if (info->FileSize == 0 && writable) { /* New file? Fill it. */
|
||||
/* If the mixin file is marked read-only take this as a hint that it shall not be initialized. */
|
||||
if (FLAGS_SET(info->Attribute, EFI_FILE_READ_ONLY))
|
||||
return log_debug_status(EFI_WRITE_PROTECTED, "Boot secret mixin file '%ls' is marked read-only, not initializing it.", BOOT_SECRET_MIXIN_PATH);
|
||||
|
||||
return setup_secret_mixin(handle, seed_table, ret_mixin);
|
||||
}
|
||||
|
||||
/* If the mixin file is too small we won't overwrite it (in order to not destroy some potentially
|
||||
* load bearing key), but we won't use it either. */
|
||||
|
||||
@@ -1326,6 +1326,8 @@ static EFI_STATUS boot_entry_bump_counters(BootEntry *entry) {
|
||||
old_path = xasprintf("%ls\\%ls", entry->directory, entry->current_name);
|
||||
|
||||
err = root->Open(root, &handle, old_path, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0ULL);
|
||||
if (EFI_STATUS_IS_WRITE_REFUSED(err))
|
||||
goto read_only;
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status(err, "Error opening boot entry '%ls': %m", old_path);
|
||||
|
||||
@@ -1333,6 +1335,11 @@ static EFI_STATUS boot_entry_bump_counters(BootEntry *entry) {
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status(err, "Error getting boot entry file info: %m");
|
||||
|
||||
/* If the boot entry file is marked read-only take this as a hint that the boot counter logic shall
|
||||
* not be applied to it, and skip it. */
|
||||
if (FLAGS_SET(file_info->Attribute, EFI_FILE_READ_ONLY))
|
||||
goto read_only;
|
||||
|
||||
/* And rename the file */
|
||||
strcpy16(file_info->FileName, entry->next_name);
|
||||
err = handle->SetInfo(handle, MAKE_GUID_PTR(EFI_FILE_INFO), file_info_size, file_info);
|
||||
@@ -1357,6 +1364,10 @@ static EFI_STATUS boot_entry_bump_counters(BootEntry *entry) {
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
|
||||
read_only:
|
||||
log_debug("Boot entry '%ls' is read-only, skipping boot counter logic.", old_path);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
static EFI_STATUS call_image_start(const BootEntry *entry, EFI_FILE *root_dir, EFI_HANDLE parent_image);
|
||||
|
||||
+42
-1
@@ -21,6 +21,8 @@
|
||||
/* Some basic domain separation in case somebody uses this data elsewhere */
|
||||
#define HASH_LABEL "systemd-boot random seed label v1"
|
||||
|
||||
#define RANDOM_SEED_PATH u"\\loader\\random-seed"
|
||||
|
||||
static EFI_STATUS acquire_rng(void *ret, size_t size) {
|
||||
EFI_RNG_PROTOCOL *rng;
|
||||
EFI_STATUS err;
|
||||
@@ -109,6 +111,31 @@ static void validate_sha256(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool random_seed_file_read_only(EFI_FILE *root_dir) {
|
||||
_cleanup_file_close_ EFI_FILE *handle = NULL;
|
||||
_cleanup_free_ EFI_FILE_INFO *info = NULL;
|
||||
EFI_STATUS err;
|
||||
|
||||
assert(root_dir);
|
||||
|
||||
/* Checks whether the random seed file exists and has the read-only file attribute set. */
|
||||
|
||||
err = root_dir->Open(root_dir, &handle, (char16_t *) RANDOM_SEED_PATH, EFI_FILE_MODE_READ, 0);
|
||||
if (err != EFI_SUCCESS) {
|
||||
if (err != EFI_NOT_FOUND)
|
||||
log_debug_status(err, "Failed to open random seed file for reading, ignoring: %m");
|
||||
return false;
|
||||
}
|
||||
|
||||
err = get_file_info(handle, &info, /* ret_size= */ NULL);
|
||||
if (err != EFI_SUCCESS) {
|
||||
log_debug_status(err, "Failed to get file info of random seed file, ignoring: %m");
|
||||
return false;
|
||||
}
|
||||
|
||||
return FLAGS_SET(info->Attribute, EFI_FILE_READ_ONLY);
|
||||
}
|
||||
|
||||
EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
|
||||
uint8_t random_bytes[DESIRED_SEED_SIZE], hash_key[HASH_VALUE_SIZE];
|
||||
_cleanup_free_ struct linux_efi_random_seed *new_seed_table = NULL;
|
||||
@@ -143,6 +170,13 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/* Similarly, if the random seed file is marked read-only, take this as a hint that the seed shall
|
||||
* not be updated — and hence not be used either, since a seed we cannot update would be the same on
|
||||
* every boot. This provides a way to explicitly turn off random seed handling, for example for
|
||||
* pre-built OS images replicated to many systems. */
|
||||
if (random_seed_file_read_only(root_dir))
|
||||
goto read_only;
|
||||
|
||||
/* hash = LABEL || sizeof(input1) || input1 || ... || sizeof(inputN) || inputN */
|
||||
sha256_init_ctx(&hash);
|
||||
|
||||
@@ -200,7 +234,7 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
|
||||
err = root_dir->Open(
|
||||
root_dir,
|
||||
&handle,
|
||||
(char16_t *) u"\\loader\\random-seed",
|
||||
(char16_t *) RANDOM_SEED_PATH,
|
||||
EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
|
||||
0);
|
||||
if (err == EFI_NOT_FOUND && seeded_by_efi) {
|
||||
@@ -252,6 +286,9 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status(err, "Failed to get file info for random seed: %m");
|
||||
|
||||
if (FLAGS_SET(info->Attribute, EFI_FILE_READ_ONLY))
|
||||
goto read_only;
|
||||
|
||||
/* Treat a short file just like a freshly created one for robustness reasons: consider a case
|
||||
* where in a previous run a file was just created and the system was then powered off. In
|
||||
* such a case the file will already exist, but be too short. */
|
||||
@@ -387,4 +424,8 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
|
||||
read_only:
|
||||
log_debug("Random seed file is read-only, not updating random seed.");
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user