uboot/lib/efi_loader/efi_var_common.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * UEFI runtime variable services
   4 *
   5 * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
   6 * Copyright (c) 2020 Linaro Limited, Author: AKASHI Takahiro
   7 */
   8
   9#include <common.h>
  10#include <efi_loader.h>
  11#include <efi_variable.h>
  12
  13enum efi_secure_mode {
  14        EFI_MODE_SETUP,
  15        EFI_MODE_USER,
  16        EFI_MODE_AUDIT,
  17        EFI_MODE_DEPLOYED,
  18};
  19
  20struct efi_auth_var_name_type {
  21        const u16 *name;
  22        const efi_guid_t *guid;
  23        const enum efi_auth_var_type type;
  24};
  25
  26static const struct efi_auth_var_name_type name_type[] = {
  27        {u"PK", &efi_global_variable_guid, EFI_AUTH_VAR_PK},
  28        {u"KEK", &efi_global_variable_guid, EFI_AUTH_VAR_KEK},
  29        {u"db",  &efi_guid_image_security_database, EFI_AUTH_VAR_DB},
  30        {u"dbx",  &efi_guid_image_security_database, EFI_AUTH_VAR_DBX},
  31        /* not used yet
  32        {u"dbt",  &efi_guid_image_security_database, EFI_AUTH_VAR_DBT},
  33        {u"dbr",  &efi_guid_image_security_database, EFI_AUTH_VAR_DBR},
  34        */
  35};
  36
  37static bool efi_secure_boot;
  38static enum efi_secure_mode efi_secure_mode;
  39
  40/**
  41 * efi_efi_get_variable() - retrieve value of a UEFI variable
  42 *
  43 * This function implements the GetVariable runtime service.
  44 *
  45 * See the Unified Extensible Firmware Interface (UEFI) specification for
  46 * details.
  47 *
  48 * @variable_name:      name of the variable
  49 * @vendor:             vendor GUID
  50 * @attributes:         attributes of the variable
  51 * @data_size:          size of the buffer to which the variable value is copied
  52 * @data:               buffer to which the variable value is copied
  53 * Return:              status code
  54 */
  55efi_status_t EFIAPI efi_get_variable(u16 *variable_name,
  56                                     const efi_guid_t *vendor, u32 *attributes,
  57                                     efi_uintn_t *data_size, void *data)
  58{
  59        efi_status_t ret;
  60
  61        EFI_ENTRY("\"%ls\" %pUl %p %p %p", variable_name, vendor, attributes,
  62                  data_size, data);
  63
  64        ret = efi_get_variable_int(variable_name, vendor, attributes,
  65                                   data_size, data, NULL);
  66
  67        /* Remove EFI_VARIABLE_READ_ONLY flag */
  68        if (attributes)
  69                *attributes &= EFI_VARIABLE_MASK;
  70
  71        return EFI_EXIT(ret);
  72}
  73
  74/**
  75 * efi_set_variable() - set value of a UEFI variable
  76 *
  77 * This function implements the SetVariable runtime service.
  78 *
  79 * See the Unified Extensible Firmware Interface (UEFI) specification for
  80 * details.
  81 *
  82 * @variable_name:      name of the variable
  83 * @vendor:             vendor GUID
  84 * @attributes:         attributes of the variable
  85 * @data_size:          size of the buffer with the variable value
  86 * @data:               buffer with the variable value
  87 * Return:              status code
  88 */
  89efi_status_t EFIAPI efi_set_variable(u16 *variable_name,
  90                                     const efi_guid_t *vendor, u32 attributes,
  91                                     efi_uintn_t data_size, const void *data)
  92{
  93        efi_status_t ret;
  94
  95        EFI_ENTRY("\"%ls\" %pUl %x %zu %p", variable_name, vendor, attributes,
  96                  data_size, data);
  97
  98        /* Make sure that the EFI_VARIABLE_READ_ONLY flag is not set */
  99        if (attributes & ~(u32)EFI_VARIABLE_MASK)
 100                ret = EFI_INVALID_PARAMETER;
 101        else
 102                ret = efi_set_variable_int(variable_name, vendor, attributes,
 103                                           data_size, data, true);
 104
 105        return EFI_EXIT(ret);
 106}
 107
 108/**
 109 * efi_get_next_variable_name() - enumerate the current variable names
 110 *
 111 * @variable_name_size: size of variable_name buffer in byte
 112 * @variable_name:      name of uefi variable's name in u16
 113 * @vendor:             vendor's guid
 114 *
 115 * See the Unified Extensible Firmware Interface (UEFI) specification for
 116 * details.
 117 *
 118 * Return: status code
 119 */
 120efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size,
 121                                               u16 *variable_name,
 122                                               efi_guid_t *vendor)
 123{
 124        efi_status_t ret;
 125
 126        EFI_ENTRY("%p \"%ls\" %pUl", variable_name_size, variable_name, vendor);
 127
 128        ret = efi_get_next_variable_name_int(variable_name_size, variable_name,
 129                                             vendor);
 130
 131        return EFI_EXIT(ret);
 132}
 133
 134/**
 135 * efi_query_variable_info() - get information about EFI variables
 136 *
 137 * This function implements the QueryVariableInfo() runtime service.
 138 *
 139 * See the Unified Extensible Firmware Interface (UEFI) specification for
 140 * details.
 141 *
 142 * @attributes:                         bitmask to select variables to be
 143 *                                      queried
 144 * @maximum_variable_storage_size:      maximum size of storage area for the
 145 *                                      selected variable types
 146 * @remaining_variable_storage_size:    remaining size of storage are for the
 147 *                                      selected variable types
 148 * @maximum_variable_size:              maximum size of a variable of the
 149 *                                      selected type
 150 * Returns:                             status code
 151 */
 152efi_status_t EFIAPI efi_query_variable_info(
 153                        u32 attributes, u64 *maximum_variable_storage_size,
 154                        u64 *remaining_variable_storage_size,
 155                        u64 *maximum_variable_size)
 156{
 157        efi_status_t ret;
 158
 159        EFI_ENTRY("%x %p %p %p", attributes, maximum_variable_storage_size,
 160                  remaining_variable_storage_size, maximum_variable_size);
 161
 162        ret = efi_query_variable_info_int(attributes,
 163                                          maximum_variable_storage_size,
 164                                          remaining_variable_storage_size,
 165                                          maximum_variable_size);
 166
 167        return EFI_EXIT(ret);
 168}
 169
 170efi_status_t __efi_runtime EFIAPI
 171efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
 172                         u32 *attributes, efi_uintn_t *data_size, void *data)
 173{
 174        efi_status_t ret;
 175
 176        ret = efi_get_variable_mem(variable_name, guid, attributes, data_size, data, NULL);
 177
 178        /* Remove EFI_VARIABLE_READ_ONLY flag */
 179        if (attributes)
 180                *attributes &= EFI_VARIABLE_MASK;
 181
 182        return ret;
 183}
 184
 185efi_status_t __efi_runtime EFIAPI
 186efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
 187                                   u16 *variable_name, efi_guid_t *guid)
 188{
 189        return efi_get_next_variable_name_mem(variable_name_size, variable_name, guid);
 190}
 191
 192/**
 193 * efi_set_secure_state - modify secure boot state variables
 194 * @secure_boot:        value of SecureBoot
 195 * @setup_mode:         value of SetupMode
 196 * @audit_mode:         value of AuditMode
 197 * @deployed_mode:      value of DeployedMode
 198 *
 199 * Modify secure boot status related variables as indicated.
 200 *
 201 * Return:              status code
 202 */
 203static efi_status_t efi_set_secure_state(u8 secure_boot, u8 setup_mode,
 204                                         u8 audit_mode, u8 deployed_mode)
 205{
 206        efi_status_t ret;
 207        const u32 attributes_ro = EFI_VARIABLE_BOOTSERVICE_ACCESS |
 208                                  EFI_VARIABLE_RUNTIME_ACCESS |
 209                                  EFI_VARIABLE_READ_ONLY;
 210        const u32 attributes_rw = EFI_VARIABLE_BOOTSERVICE_ACCESS |
 211                                  EFI_VARIABLE_RUNTIME_ACCESS;
 212
 213        efi_secure_boot = secure_boot;
 214
 215        ret = efi_set_variable_int(L"SecureBoot", &efi_global_variable_guid,
 216                                   attributes_ro, sizeof(secure_boot),
 217                                   &secure_boot, false);
 218        if (ret != EFI_SUCCESS)
 219                goto err;
 220
 221        ret = efi_set_variable_int(L"SetupMode", &efi_global_variable_guid,
 222                                   attributes_ro, sizeof(setup_mode),
 223                                   &setup_mode, false);
 224        if (ret != EFI_SUCCESS)
 225                goto err;
 226
 227        ret = efi_set_variable_int(L"AuditMode", &efi_global_variable_guid,
 228                                   audit_mode || setup_mode ?
 229                                   attributes_ro : attributes_rw,
 230                                   sizeof(audit_mode), &audit_mode, false);
 231        if (ret != EFI_SUCCESS)
 232                goto err;
 233
 234        ret = efi_set_variable_int(L"DeployedMode",
 235                                   &efi_global_variable_guid,
 236                                   audit_mode || deployed_mode || setup_mode ?
 237                                   attributes_ro : attributes_rw,
 238                                   sizeof(deployed_mode), &deployed_mode,
 239                                   false);
 240err:
 241        return ret;
 242}
 243
 244/**
 245 * efi_transfer_secure_state - handle a secure boot state transition
 246 * @mode:       new state
 247 *
 248 * Depending on @mode, secure boot related variables are updated.
 249 * Those variables are *read-only* for users, efi_set_variable_int()
 250 * is called here.
 251 *
 252 * Return:      status code
 253 */
 254static efi_status_t efi_transfer_secure_state(enum efi_secure_mode mode)
 255{
 256        efi_status_t ret;
 257
 258        EFI_PRINT("Switching secure state from %d to %d\n", efi_secure_mode,
 259                  mode);
 260
 261        if (mode == EFI_MODE_DEPLOYED) {
 262                ret = efi_set_secure_state(1, 0, 0, 1);
 263                if (ret != EFI_SUCCESS)
 264                        goto err;
 265        } else if (mode == EFI_MODE_AUDIT) {
 266                ret = efi_set_variable_int(L"PK", &efi_global_variable_guid,
 267                                           EFI_VARIABLE_BOOTSERVICE_ACCESS |
 268                                           EFI_VARIABLE_RUNTIME_ACCESS,
 269                                           0, NULL, false);
 270                if (ret != EFI_SUCCESS)
 271                        goto err;
 272
 273                ret = efi_set_secure_state(0, 1, 1, 0);
 274                if (ret != EFI_SUCCESS)
 275                        goto err;
 276        } else if (mode == EFI_MODE_USER) {
 277                ret = efi_set_secure_state(1, 0, 0, 0);
 278                if (ret != EFI_SUCCESS)
 279                        goto err;
 280        } else if (mode == EFI_MODE_SETUP) {
 281                ret = efi_set_secure_state(0, 1, 0, 0);
 282                if (ret != EFI_SUCCESS)
 283                        goto err;
 284        } else {
 285                return EFI_INVALID_PARAMETER;
 286        }
 287
 288        efi_secure_mode = mode;
 289
 290        return EFI_SUCCESS;
 291
 292err:
 293        /* TODO: What action should be taken here? */
 294        printf("ERROR: Secure state transition failed\n");
 295        return ret;
 296}
 297
 298efi_status_t efi_init_secure_state(void)
 299{
 300        enum efi_secure_mode mode = EFI_MODE_SETUP;
 301        u8 efi_vendor_keys = 0;
 302        efi_uintn_t size = 0;
 303        efi_status_t ret;
 304
 305        ret = efi_get_variable_int(L"PK", &efi_global_variable_guid,
 306                                   NULL, &size, NULL, NULL);
 307        if (ret == EFI_BUFFER_TOO_SMALL) {
 308                if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT))
 309                        mode = EFI_MODE_USER;
 310        }
 311
 312        ret = efi_transfer_secure_state(mode);
 313        if (ret != EFI_SUCCESS)
 314                return ret;
 315
 316        /* As we do not provide vendor keys this variable is always 0. */
 317        ret = efi_set_variable_int(L"VendorKeys",
 318                                   &efi_global_variable_guid,
 319                                   EFI_VARIABLE_BOOTSERVICE_ACCESS |
 320                                   EFI_VARIABLE_RUNTIME_ACCESS |
 321                                   EFI_VARIABLE_READ_ONLY,
 322                                   sizeof(efi_vendor_keys),
 323                                   &efi_vendor_keys, false);
 324        return ret;
 325}
 326
 327/**
 328 * efi_secure_boot_enabled - return if secure boot is enabled or not
 329 *
 330 * Return:      true if enabled, false if disabled
 331 */
 332bool efi_secure_boot_enabled(void)
 333{
 334        return efi_secure_boot;
 335}
 336
 337enum efi_auth_var_type efi_auth_var_get_type(u16 *name, const efi_guid_t *guid)
 338{
 339        for (size_t i = 0; i < ARRAY_SIZE(name_type); ++i) {
 340                if (!u16_strcmp(name, name_type[i].name) &&
 341                    !guidcmp(guid, name_type[i].guid))
 342                        return name_type[i].type;
 343        }
 344        return EFI_AUTH_VAR_NONE;
 345}
 346