[Skiboot] [PATCH v2 4/6] secvar/edk2: change get_key_authority to return a list of variables instead of their names
Eric Richter
erichte at linux.ibm.com
Thu Nov 4 02:35:05 AEDT 2021
On 11/3/21 12:04 AM, Daniel Axtens wrote:
> Eric Richter <erichte at linux.ibm.com> writes:
>
>> The current get_key_authority function returns a list of variable names that
>> can authorize updates to a particular variable (e.g. "KEK" can authorize
>> updates to "db").
>>
>> As the names will have to be fetched anyway via calls to find_secvar(), this
>> patch changes the behavior to operate on secvars themselves instead of just
>> the names. It takes in a secvar reference, and returns a list of secvar
>> references that hold the proper authority, thus cleaning up a few
>> extra unnecessary temporary variables.
>>
>> Signed-off-by: Eric Richter <erichte at linux.ibm.com>
>> ---
>> libstb/secvar/backend/edk2-compat-process.c | 32 +++++++++------------
>> 1 file changed, 14 insertions(+), 18 deletions(-)
>>
>> diff --git a/libstb/secvar/backend/edk2-compat-process.c b/libstb/secvar/backend/edk2-compat-process.c
>> index d69e066f..cdc95737 100644
>> --- a/libstb/secvar/backend/edk2-compat-process.c
>> +++ b/libstb/secvar/backend/edk2-compat-process.c
>> @@ -72,17 +72,17 @@ static char *char_to_wchar(const char *key, const size_t keylen)
>> }
>>
>> /* Returns the authority that can sign the given key update */
>> -static void get_key_authority(const char *ret[3], const char *key)
>> +static void get_key_authority(const struct secvar *ret[3], const struct secvar *update, struct list_head *bank)
>> {
>> int i = 0;
>>
>> - if (key_equals(key, "PK")) {
>> - ret[i++] = "PK";
>> - } else if (key_equals(key, "KEK")) {
>> - ret[i++] = "PK";
>> - } else if (key_equals(key, "db") || key_equals(key, "dbx")) {
>> - ret[i++] = "KEK";
>> - ret[i++] = "PK";
>> + if (key_equals(update->key, "PK")) {
>> + ret[i++] = find_secvar("PK", 3, bank);
>> + } else if (key_equals(update->key, "KEK")) {
>> + ret[i++] = find_secvar("PK", 3, bank);
>> + } else if (key_equals(update->key, "db") || key_equals(update->key, "dbx")) {
>> + ret[i++] = find_secvar("KEK", 4, bank);
>> + ret[i++] = find_secvar("PK", 3, bank);
>> }
>
> If you have PK but not KEK, and you try to update db, ret will be:
> {NULL, <secvar: PK>, NULL}. This will cause the for loop further down in
> process_update to fall apart because it checks for NULLs.
>
Non-obvious quirk I will update with a comment: These variables always exist
in the bank due to .pre_process() generating empty ones if they aren't loaded
from storage.
The old code effectively did this anyway, I just moved the find_secvar() calls
in here to shorten the loop.
>>
>> ret[i] = NULL;
>> @@ -701,9 +701,8 @@ int process_update(const struct secvar *update, char **newesl,
>> struct efi_variable_authentication_2 *auth = NULL;
>> void *auth_buffer = NULL;
>> int auth_buffer_size = 0;
>> - const char *key_authority[3];
>> + const struct secvar *key_authority[3];
>> char *hash = NULL;
>> - struct secvar *avar = NULL;
>> int rc = 0;
>> int i;
>>
>> @@ -770,7 +769,7 @@ int process_update(const struct secvar *update, char **newesl,
>> }
>>
>> /* Get the authority to verify the signature */
>> - get_key_authority(key_authority, update->key);
>> + get_key_authority(key_authority, update, bank);
>>
>> /*
>> * Try for all the authorities that are allowed to sign.
>> @@ -778,19 +777,16 @@ int process_update(const struct secvar *update, char **newesl,
>> */
>> for (i = 0; key_authority[i] != NULL; i++) {
>
> As I mentioned above, this might go wrong if you're updating db(x) and
> have PK but no KEK. I think you probably need to iterate over
> ARRAY_SIZE(key_authority) and just `continue` if NULL?
>
>> prlog(PR_DEBUG, "key is %s\n", update->key);
>> - prlog(PR_DEBUG, "key authority is %s\n", key_authority[i]);
>> - avar = find_secvar(key_authority[i],
>> - strlen(key_authority[i]) + 1,
>> - bank);
>> - if (!avar || !avar->data_size)
>> + prlog(PR_DEBUG, "key authority is %s\n", key_authority[i]->key);
>> + if (!key_authority[i] || !key_authority[i]->data_size)
>> continue;
>
> I thought you were doing an undefined behaviour there: dereferencing
> key_authority[i] before you check whether or not it is NULL. However,
> key_authority is already not NULL by virtue of the check in the for
> loop. So really the test in the `if` can be simplified. It did make
> sense before because avar lookup could give you NULL.
>
Ah, yup. Find/replace at its best.
> If you rejig the loop you'll need to reevaluate this, of course.
I'll probably end up doing this. The variables won't be NULL, but I
won't leave that to chance in case they ever are.
>
> Kind regards,
> Daniel
>
More information about the Skiboot
mailing list