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