From: Lennart Poettering Date: Mon, 13 Jul 2026 13:45:49 +0000 (+0200) Subject: boot: skip random seed handling if seed file is marked read-only X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=78f81f02e89adf90522a7ca986eec79b9253b411;p=thirdparty%2Fsystemd.git boot: skip random seed handling if seed file is marked read-only If the read-only FAT file attribute is set on /loader/random-seed, don't update the seed file — and hence don't use it either, since a seed we cannot update would be the same on every boot. This gives users an explicit way to turn off random seed handling by marking the file read-only, useful for example in pre-built OS images that are replicated to many systems, where the baked-in seed is shared and hence must not be credited. The check is done upfront in process_random_seed(), before any other work, mirroring the existing check for read-only volumes. This covers both systemd-boot and systemd-stub, which share this code. Inspired-by: #42979 --- diff --git a/docs/RANDOM_SEEDS.md b/docs/RANDOM_SEEDS.md index 484cc4dbf72..3dd135baf83 100644 --- a/docs/RANDOM_SEEDS.md +++ b/docs/RANDOM_SEEDS.md @@ -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. diff --git a/man/systemd-boot.xml b/man/systemd-boot.xml index 2162c7ffb2b..6f8ae255605 100644 --- a/man/systemd-boot.xml +++ b/man/systemd-boot.xml @@ -390,7 +390,10 @@ /EFI/Linux/ on the ESP and the Extended Boot Loader partition. Optionally, a random seed for early boot entropy pool provisioning is stored in - /loader/random-seed in the ESP. + /loader/random-seed 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. During initialization, systemd-boot automatically loads all driver files placed in the /EFI/systemd/drivers/ directory of the ESP. The files placed there must have diff --git a/src/boot/random-seed.c b/src/boot/random-seed.c index e10e765b7fe..ca870739769 100644 --- a/src/boot/random-seed.c +++ b/src/boot/random-seed.c @@ -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; }