efi_loader: variable: add VendorKeys variable
authorAKASHI Takahiro <takahiro.akashi@linaro.org>
Tue, 14 Apr 2020 02:51:43 +0000 (11:51 +0900)
committerHeinrich Schuchardt <xypron.glpk@gmx.de>
Thu, 16 Apr 2020 06:12:46 +0000 (08:12 +0200)
The following variable is exported as UEFI specification defines:
VendorKeys: whether the system is configured to use only vendor-provided
    keys or not
The value will have to be modified if a platform has its own way of
initializing signature database, in particular, PK.

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
lib/efi_loader/efi_variable.c

index fd5c41f830b1e5181b376942a56dd0f0b327af51..7df881a74b4496d24e44e930926c9d0e51ff4508 100644 (file)
@@ -26,6 +26,7 @@ enum efi_secure_mode {
 const efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
 static bool efi_secure_boot;
 static int efi_secure_mode;
+static u8 efi_vendor_keys;
 
 #define READ_ONLY BIT(31)
 
@@ -344,6 +345,8 @@ static efi_status_t efi_transfer_secure_state(enum efi_secure_mode mode)
                return EFI_INVALID_PARAMETER;
        }
 
+       efi_secure_mode = mode;
+
        return EFI_SUCCESS;
 
 err:
@@ -359,16 +362,46 @@ err:
  */
 static efi_status_t efi_init_secure_state(void)
 {
-       efi_uintn_t size = 0;
+       enum efi_secure_mode mode;
+       efi_uintn_t size;
        efi_status_t ret;
 
+       /*
+        * TODO:
+        * Since there is currently no "platform-specific" installation
+        * method of Platform Key, we can't say if VendorKeys is 0 or 1
+        * precisely.
+        */
+
+       size = 0;
        ret = EFI_CALL(efi_get_variable(L"PK", &efi_global_variable_guid,
                                        NULL, &size, NULL));
-       if (ret == EFI_BUFFER_TOO_SMALL && IS_ENABLED(CONFIG_EFI_SECURE_BOOT))
-               ret = efi_transfer_secure_state(EFI_MODE_USER);
-       else
-               ret = efi_transfer_secure_state(EFI_MODE_SETUP);
+       if (ret == EFI_BUFFER_TOO_SMALL) {
+               if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT))
+                       mode = EFI_MODE_USER;
+               else
+                       mode = EFI_MODE_SETUP;
+
+               efi_vendor_keys = 0;
+       } else if (ret == EFI_NOT_FOUND) {
+               mode = EFI_MODE_SETUP;
+               efi_vendor_keys = 1;
+       } else {
+               goto err;
+       }
 
+       ret = efi_transfer_secure_state(mode);
+       if (ret == EFI_SUCCESS)
+               ret = efi_set_variable_internal(L"VendorKeys",
+                                               &efi_global_variable_guid,
+                                               EFI_VARIABLE_BOOTSERVICE_ACCESS
+                                                | EFI_VARIABLE_RUNTIME_ACCESS
+                                                | READ_ONLY,
+                                               sizeof(efi_vendor_keys),
+                                               &efi_vendor_keys,
+                                               false);
+
+err:
        return ret;
 }
 
@@ -1125,6 +1158,8 @@ out:
        if (env_set(native_name, val)) {
                ret = EFI_DEVICE_ERROR;
        } else {
+               bool vendor_keys_modified = false;
+
                if ((u16_strcmp(variable_name, L"PK") == 0 &&
                     guidcmp(vendor, &efi_global_variable_guid) == 0)) {
                        ret = efi_transfer_secure_state(
@@ -1132,8 +1167,30 @@ out:
                                                  EFI_MODE_USER));
                        if (ret != EFI_SUCCESS)
                                goto err;
+
+                       if (efi_secure_mode != EFI_MODE_SETUP)
+                               vendor_keys_modified = true;
+               } else if ((u16_strcmp(variable_name, L"KEK") == 0 &&
+                    guidcmp(vendor, &efi_global_variable_guid) == 0)) {
+                       if (efi_secure_mode != EFI_MODE_SETUP)
+                               vendor_keys_modified = true;
+               }
+
+               /* update VendorKeys */
+               if (vendor_keys_modified & efi_vendor_keys) {
+                       efi_vendor_keys = 0;
+                       ret = efi_set_variable_internal(
+                                               L"VendorKeys",
+                                               &efi_global_variable_guid,
+                                               EFI_VARIABLE_BOOTSERVICE_ACCESS
+                                                | EFI_VARIABLE_RUNTIME_ACCESS
+                                                | READ_ONLY,
+                                               sizeof(efi_vendor_keys),
+                                               &efi_vendor_keys,
+                                               false);
+               } else {
+                       ret = EFI_SUCCESS;
                }
-               ret = EFI_SUCCESS;
        }
 
 err: