@@ -69,21 +69,29 @@ efi_status_t efi_random_get_seed(void)
6969 efi_guid_t rng_table_guid = LINUX_EFI_RANDOM_SEED_TABLE_GUID ;
7070 struct linux_efi_random_seed * prev_seed , * seed = NULL ;
7171 int prev_seed_size = 0 , seed_size = EFI_RANDOM_SEED_SIZE ;
72+ unsigned long nv_seed_size = 0 , offset = 0 ;
7273 efi_rng_protocol_t * rng = NULL ;
7374 efi_status_t status ;
7475
7576 status = efi_bs_call (locate_protocol , & rng_proto , NULL , (void * * )& rng );
7677 if (status != EFI_SUCCESS )
78+ seed_size = 0 ;
79+
80+ // Call GetVariable() with a zero length buffer to obtain the size
81+ get_efi_var (L"RandomSeed" , & rng_table_guid , NULL , & nv_seed_size , NULL );
82+ if (!seed_size && !nv_seed_size )
7783 return status ;
7884
85+ seed_size += nv_seed_size ;
86+
7987 /*
8088 * Check whether a seed was provided by a prior boot stage. In that
8189 * case, instead of overwriting it, let's create a new buffer that can
8290 * hold both, and concatenate the existing and the new seeds.
8391 * Note that we should read the seed size with caution, in case the
8492 * table got corrupted in memory somehow.
8593 */
86- prev_seed = get_efi_config_table (LINUX_EFI_RANDOM_SEED_TABLE_GUID );
94+ prev_seed = get_efi_config_table (rng_table_guid );
8795 if (prev_seed && prev_seed -> size <= 512U ) {
8896 prev_seed_size = prev_seed -> size ;
8997 seed_size += prev_seed_size ;
@@ -102,25 +110,53 @@ efi_status_t efi_random_get_seed(void)
102110 goto err_warn ;
103111 }
104112
105- status = efi_call_proto (rng , get_rng , & rng_algo_raw ,
106- EFI_RANDOM_SEED_SIZE , seed -> bits );
107-
108- if (status == EFI_UNSUPPORTED )
109- /*
110- * Use whatever algorithm we have available if the raw algorithm
111- * is not implemented.
112- */
113- status = efi_call_proto (rng , get_rng , NULL ,
113+ if (rng ) {
114+ status = efi_call_proto (rng , get_rng , & rng_algo_raw ,
114115 EFI_RANDOM_SEED_SIZE , seed -> bits );
115116
116- if (status != EFI_SUCCESS )
117+ if (status == EFI_UNSUPPORTED )
118+ /*
119+ * Use whatever algorithm we have available if the raw algorithm
120+ * is not implemented.
121+ */
122+ status = efi_call_proto (rng , get_rng , NULL ,
123+ EFI_RANDOM_SEED_SIZE , seed -> bits );
124+
125+ if (status == EFI_SUCCESS )
126+ offset = EFI_RANDOM_SEED_SIZE ;
127+ }
128+
129+ if (nv_seed_size ) {
130+ status = get_efi_var (L"RandomSeed" , & rng_table_guid , NULL ,
131+ & nv_seed_size , seed -> bits + offset );
132+
133+ if (status == EFI_SUCCESS )
134+ /*
135+ * We delete the seed here, and /hope/ that this causes
136+ * EFI to also zero out its representation on disk.
137+ * This is somewhat idealistic, but overwriting the
138+ * variable with zeros is likely just as fraught too.
139+ * TODO: in the future, maybe we can hash it forward
140+ * instead, and write a new seed.
141+ */
142+ status = set_efi_var (L"RandomSeed" , & rng_table_guid , 0 ,
143+ 0 , NULL );
144+
145+ if (status == EFI_SUCCESS )
146+ offset += nv_seed_size ;
147+ else
148+ memzero_explicit (seed -> bits + offset , nv_seed_size );
149+ }
150+
151+ if (!offset )
117152 goto err_freepool ;
118153
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 );
154+ if ( prev_seed_size ) {
155+ memcpy ( seed -> bits + offset , prev_seed -> bits , prev_seed_size );
156+ offset += prev_seed_size ;
157+ }
123158
159+ seed -> size = offset ;
124160 status = efi_bs_call (install_configuration_table , & rng_table_guid , seed );
125161 if (status != EFI_SUCCESS )
126162 goto err_freepool ;
@@ -135,7 +171,7 @@ efi_status_t efi_random_get_seed(void)
135171err_freepool :
136172 memzero_explicit (seed , struct_size (seed , bits , seed_size ));
137173 efi_bs_call (free_pool , seed );
138- efi_warn ("Failed to obtain seed from EFI_RNG_PROTOCOL\n" );
174+ efi_warn ("Failed to obtain seed from EFI_RNG_PROTOCOL or EFI variable \n" );
139175err_warn :
140176 if (prev_seed )
141177 efi_warn ("Retaining bootloader-supplied seed only" );
0 commit comments