hc
2024-05-11 04dd17822334871b23ea2862f7798fb0e0007777
kernel/drivers/firmware/efi/libstub/random.c
....@@ -67,8 +67,9 @@
6767 efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID;
6868 efi_guid_t rng_algo_raw = EFI_RNG_ALGORITHM_RAW;
6969 efi_guid_t rng_table_guid = LINUX_EFI_RANDOM_SEED_TABLE_GUID;
70
+ struct linux_efi_random_seed *prev_seed, *seed = NULL;
71
+ int prev_seed_size = 0, seed_size = EFI_RANDOM_SEED_SIZE;
7072 efi_rng_protocol_t *rng = NULL;
71
- struct linux_efi_random_seed *seed = NULL;
7273 efi_status_t status;
7374
7475 status = efi_bs_call(locate_protocol, &rng_proto, NULL, (void **)&rng);
....@@ -76,18 +77,33 @@
7677 return status;
7778
7879 /*
80
+ * Check whether a seed was provided by a prior boot stage. In that
81
+ * case, instead of overwriting it, let's create a new buffer that can
82
+ * hold both, and concatenate the existing and the new seeds.
83
+ * Note that we should read the seed size with caution, in case the
84
+ * table got corrupted in memory somehow.
85
+ */
86
+ prev_seed = get_efi_config_table(LINUX_EFI_RANDOM_SEED_TABLE_GUID);
87
+ if (prev_seed && prev_seed->size <= 512U) {
88
+ prev_seed_size = prev_seed->size;
89
+ seed_size += prev_seed_size;
90
+ }
91
+
92
+ /*
7993 * Use EFI_ACPI_RECLAIM_MEMORY here so that it is guaranteed that the
8094 * allocation will survive a kexec reboot (although we refresh the seed
8195 * beforehand)
8296 */
8397 status = efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY,
84
- sizeof(*seed) + EFI_RANDOM_SEED_SIZE,
98
+ struct_size(seed, bits, seed_size),
8599 (void **)&seed);
86
- if (status != EFI_SUCCESS)
87
- return status;
100
+ if (status != EFI_SUCCESS) {
101
+ efi_warn("Failed to allocate memory for RNG seed.\n");
102
+ goto err_warn;
103
+ }
88104
89105 status = efi_call_proto(rng, get_rng, &rng_algo_raw,
90
- EFI_RANDOM_SEED_SIZE, seed->bits);
106
+ EFI_RANDOM_SEED_SIZE, seed->bits);
91107
92108 if (status == EFI_UNSUPPORTED)
93109 /*
....@@ -100,14 +116,28 @@
100116 if (status != EFI_SUCCESS)
101117 goto err_freepool;
102118
103
- seed->size = EFI_RANDOM_SEED_SIZE;
119
+ seed->size = seed_size;
120
+ if (prev_seed_size)
121
+ memcpy(seed->bits + EFI_RANDOM_SEED_SIZE, prev_seed->bits,
122
+ prev_seed_size);
123
+
104124 status = efi_bs_call(install_configuration_table, &rng_table_guid, seed);
105125 if (status != EFI_SUCCESS)
106126 goto err_freepool;
107127
128
+ if (prev_seed_size) {
129
+ /* wipe and free the old seed if we managed to install the new one */
130
+ memzero_explicit(prev_seed->bits, prev_seed_size);
131
+ efi_bs_call(free_pool, prev_seed);
132
+ }
108133 return EFI_SUCCESS;
109134
110135 err_freepool:
136
+ memzero_explicit(seed, struct_size(seed, bits, seed_size));
111137 efi_bs_call(free_pool, seed);
138
+ efi_warn("Failed to obtain seed from EFI_RNG_PROTOCOL\n");
139
+err_warn:
140
+ if (prev_seed)
141
+ efi_warn("Retaining bootloader-supplied seed only");
112142 return status;
113143 }