1
0
mirror of https://xff.cz/git/u-boot/ synced 2025-09-01 08:42:12 +02:00
Pull request for UEFI sub-system for efi-2020-07-rc2

This pull request contains bug fixes needed due to the merged changes for
EFI secure boot.

Patches are supplied to identify EFI system partitions.
This commit is contained in:
Tom Rini
2020-04-30 15:11:06 -04:00
11 changed files with 179 additions and 140 deletions

View File

@@ -625,6 +625,7 @@ F: include/asm-generic/pe.h
F: lib/charset.c
F: lib/efi*/
F: test/py/tests/test_efi*
F: test/py/tests/test_efi*/
F: test/unicode_ut.c
F: cmd/bootefi.c
F: cmd/efidebug.c

View File

@@ -481,9 +481,7 @@ efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size)
ret = do_bootefi_exec(handle);
out:
if (mem_handle)
efi_delete_handle(mem_handle);
if (file_path)
efi_free_pool(file_path);
return ret;
}

View File

@@ -395,6 +395,7 @@ static const char * const efi_mem_type_string[] = {
[EFI_MMAP_IO] = "IO",
[EFI_MMAP_IO_PORT] = "IO PORT",
[EFI_PAL_CODE] = "PAL",
[EFI_PERSISTENT_MEMORY_TYPE] = "PERSISTENT",
};
static const struct efi_mem_attrs {
@@ -482,7 +483,7 @@ static int do_efi_show_memmap(cmd_tbl_t *cmdtp, int flag,
printf("================ %.*s %.*s ==========\n",
EFI_PHYS_ADDR_WIDTH, sep, EFI_PHYS_ADDR_WIDTH, sep);
for (i = 0, map = memmap; i < map_size / sizeof(*map); map++, i++) {
if (map->type < EFI_MAX_MEMORY_TYPE)
if (map->type < ARRAY_SIZE(efi_mem_type_string))
type = efi_mem_type_string[map->type];
else
type = "(unknown)";
@@ -682,13 +683,13 @@ static int do_efi_boot_rm(cmd_tbl_t *cmdtp, int flag,
/**
* show_efi_boot_opt_data() - dump UEFI load option
*
* @id: load option number
* @varname16: variable name
* @data: value of UEFI load option variable
* @size: size of the boot option
*
* Decode the value of UEFI load option variable and print information.
*/
static void show_efi_boot_opt_data(int id, void *data, size_t size)
static void show_efi_boot_opt_data(u16 *varname16, void *data, size_t size)
{
struct efi_load_option lo;
char *label, *p;
@@ -705,8 +706,8 @@ static void show_efi_boot_opt_data(int id, void *data, size_t size)
p = label;
utf16_utf8_strncpy(&p, lo.label, label_len16);
printf("Boot%04X:\n", id);
printf(" attributes: %c%c%c (0x%08x)\n",
printf("%ls:\nattributes: %c%c%c (0x%08x)\n",
varname16,
/* ACTIVE */
lo.attributes & LOAD_OPTION_ACTIVE ? 'A' : '-',
/* FORCE RECONNECT */
@@ -730,37 +731,32 @@ static void show_efi_boot_opt_data(int id, void *data, size_t size)
/**
* show_efi_boot_opt() - dump UEFI load option
*
* @id: Load option number
* @varname16: variable name
*
* Dump information defined by UEFI load option.
*/
static void show_efi_boot_opt(int id)
static void show_efi_boot_opt(u16 *varname16)
{
char var_name[9];
u16 var_name16[9], *p;
efi_guid_t guid;
void *data = NULL;
void *data;
efi_uintn_t size;
efi_status_t ret;
sprintf(var_name, "Boot%04X", id);
p = var_name16;
utf8_utf16_strncpy(&p, var_name, 9);
guid = efi_global_variable_guid;
size = 0;
ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size, NULL));
ret = EFI_CALL(efi_get_variable(varname16, &efi_global_variable_guid,
NULL, &size, NULL));
if (ret == EFI_BUFFER_TOO_SMALL) {
data = malloc(size);
ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size,
data));
if (!data) {
printf("ERROR: Out of memory\n");
return;
}
ret = EFI_CALL(efi_get_variable(varname16,
&efi_global_variable_guid,
NULL, &size, data));
if (ret == EFI_SUCCESS)
show_efi_boot_opt_data(id, data, size);
else if (ret == EFI_NOT_FOUND)
printf("Boot%04X: not found\n", id);
show_efi_boot_opt_data(varname16, data, size);
free(data);
}
}
static int u16_tohex(u16 c)
@@ -839,7 +835,7 @@ static int do_efi_boot_dump(cmd_tbl_t *cmdtp, int flag,
id = (id << 4) + digit;
}
if (i == 4 && !var_name16[8])
show_efi_boot_opt(id);
show_efi_boot_opt(var_name16);
}
free(var_name16);
@@ -856,8 +852,7 @@ static int do_efi_boot_dump(cmd_tbl_t *cmdtp, int flag,
*/
static int show_efi_boot_order(void)
{
efi_guid_t guid;
u16 *bootorder = NULL;
u16 *bootorder;
efi_uintn_t size;
int num, i;
char var_name[9];
@@ -868,20 +863,25 @@ static int show_efi_boot_order(void)
size_t label_len16, label_len;
efi_status_t ret;
guid = efi_global_variable_guid;
size = 0;
ret = EFI_CALL(RT->get_variable(L"BootOrder", &guid, NULL, &size,
NULL));
if (ret == EFI_BUFFER_TOO_SMALL) {
bootorder = malloc(size);
ret = EFI_CALL(RT->get_variable(L"BootOrder", &guid, NULL,
&size, bootorder));
}
ret = EFI_CALL(RT->get_variable(L"BootOrder", &efi_global_variable_guid,
NULL, &size, NULL));
if (ret != EFI_BUFFER_TOO_SMALL) {
if (ret == EFI_NOT_FOUND) {
printf("BootOrder not defined\n");
ret = CMD_RET_SUCCESS;
goto out;
} else if (ret != EFI_SUCCESS) {
return CMD_RET_SUCCESS;
} else {
return CMD_RET_FAILURE;
}
}
bootorder = malloc(size);
if (!bootorder) {
printf("ERROR: Out of memory\n");
return CMD_RET_FAILURE;
}
ret = EFI_CALL(efi_get_variable(L"BootOrder", &efi_global_variable_guid,
NULL, &size, bootorder));
if (ret != EFI_SUCCESS) {
ret = CMD_RET_FAILURE;
goto out;
}
@@ -893,11 +893,11 @@ static int show_efi_boot_order(void)
utf8_utf16_strncpy(&p16, var_name, 9);
size = 0;
ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size,
NULL));
ret = EFI_CALL(efi_get_variable(var_name16,
&efi_global_variable_guid, NULL,
&size, NULL));
if (ret != EFI_BUFFER_TOO_SMALL) {
printf("%2d: Boot%04X: (not defined)\n",
i + 1, bootorder[i]);
printf("%2d: %s: (not defined)\n", i + 1, var_name);
continue;
}
@@ -906,8 +906,9 @@ static int show_efi_boot_order(void)
ret = CMD_RET_FAILURE;
goto out;
}
ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size,
data));
ret = EFI_CALL(efi_get_variable(var_name16,
&efi_global_variable_guid, NULL,
&size, data));
if (ret != EFI_SUCCESS) {
free(data);
ret = CMD_RET_FAILURE;
@@ -926,7 +927,7 @@ static int show_efi_boot_order(void)
}
p = label;
utf16_utf8_strncpy(&p, lo.label, label_len16);
printf("%2d: Boot%04X: %s\n", i + 1, bootorder[i], label);
printf("%2d: %s: %s\n", i + 1, var_name, label);
free(label);
free(data);

View File

@@ -245,7 +245,7 @@ static void print_gpt_info(void)
printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
curr->gpt_part_info.name);
printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
curr->gpt_part_info.bootable);
curr->gpt_part_info.bootable & PART_BOOTABLE);
#ifdef CONFIG_PARTITION_UUIDS
printf("UUID %s\n", curr->gpt_part_info.uuid);
#endif
@@ -535,7 +535,7 @@ static int set_gpt_info(struct blk_desc *dev_desc,
/* bootable */
if (found_key(tok, "bootable"))
parts[i].bootable = 1;
parts[i].bootable = PART_BOOTABLE;
}
*parts_count = p_count;

View File

@@ -45,9 +45,15 @@ static inline int is_extended(int part_type)
part_type == 0x85);
}
static inline int is_bootable(dos_partition_t *p)
static int get_bootable(dos_partition_t *p)
{
return (p->sys_ind == 0xef) || (p->boot_ind == 0x80);
int ret = 0;
if (p->sys_ind == 0xef)
ret |= PART_EFI_SYSTEM_PARTITION;
if (p->boot_ind == 0x80)
ret |= PART_BOOTABLE;
return ret;
}
static void print_one_part(dos_partition_t *p, lbaint_t ext_part_sector,
@@ -60,7 +66,7 @@ static void print_one_part(dos_partition_t *p, lbaint_t ext_part_sector,
"u\t%08x-%02x\t%02x%s%s\n",
part_num, lba_start, lba_size, disksig, part_num, p->sys_ind,
(is_extended(p->sys_ind) ? " Extd" : ""),
(is_bootable(p) ? " Boot" : ""));
(get_bootable(p) ? " Boot" : ""));
}
static int test_block_type(unsigned char *buffer)
@@ -258,7 +264,7 @@ static int part_get_info_extended(struct blk_desc *dev_desc,
(char *)info->name);
/* sprintf(info->type, "%d, pt->sys_ind); */
strcpy((char *)info->type, "U-Boot");
info->bootable = is_bootable(pt);
info->bootable = get_bootable(pt);
#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
sprintf(info->uuid, "%08x-%02x", disksig, part_num);
#endif

View File

@@ -71,11 +71,15 @@ static char *print_efiname(gpt_entry *pte)
static const efi_guid_t system_guid = PARTITION_SYSTEM_GUID;
static inline int is_bootable(gpt_entry *p)
static int get_bootable(gpt_entry *p)
{
return p->attributes.fields.legacy_bios_bootable ||
!memcmp(&(p->partition_type_guid), &system_guid,
sizeof(efi_guid_t));
int ret = 0;
if (!memcmp(&p->partition_type_guid, &system_guid, sizeof(efi_guid_t)))
ret |= PART_EFI_SYSTEM_PARTITION;
if (p->attributes.fields.legacy_bios_bootable)
ret |= PART_BOOTABLE;
return ret;
}
static int validate_gpt_header(gpt_header *gpt_h, lbaint_t lba,
@@ -286,7 +290,7 @@ int part_get_info_efi(struct blk_desc *dev_desc, int part,
snprintf((char *)info->name, sizeof(info->name), "%s",
print_efiname(&gpt_pte[part - 1]));
strcpy((char *)info->type, "U-Boot");
info->bootable = is_bootable(&gpt_pte[part - 1]);
info->bootable = get_bootable(&gpt_pte[part - 1]);
#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
uuid_bin_to_str(gpt_pte[part - 1].unique_partition_guid.b, info->uuid,
UUID_STR_FORMAT_GUID);
@@ -501,7 +505,7 @@ int gpt_fill_pte(struct blk_desc *dev_desc,
memset(&gpt_e[i].attributes, 0,
sizeof(gpt_entry_attributes));
if (partitions[i].bootable)
if (partitions[i].bootable & PART_BOOTABLE)
gpt_e[i].attributes.fields.legacy_bios_bootable = 1;
/* partition name */

View File

@@ -100,47 +100,57 @@ See doc/uImage.FIT/howto.txt for an introduction to FIT images.
Configuring UEFI secure boot
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
UEFI specification[1] defines a secure way of executing UEFI images
The UEFI specification[1] defines a secure way of executing UEFI images
by verifying a signature (or message digest) of image with certificates.
This feature on U-Boot is enabled with::
CONFIG_UEFI_SECURE_BOOT=y
To make the boot sequence safe, you need to establish a chain of trust;
In UEFI secure boot, you can make it with the UEFI variables, "PK"
(Platform Key), "KEK" (Key Exchange Keys), "db" (white list database)
and "dbx" (black list database).
In UEFI secure boot the chain trust is defined by the following UEFI variables
There are many online documents that describe what UEFI secure boot is
and how it works. Please consult some of them for details.
* PK - Platform Key
* KEK - Key Exchange Keys
* db - white list database
* dbx - black list database
Here is a simple example that you can follow for your initial attempt
(Please note that the actual steps would absolutely depend on your system
and environment.):
An in depth description of UEFI secure boot is beyond the scope of this
document. Please, refer to the UEFI specification and available online
documentation. Here is a simple example that you can follow for your initial
attempt (Please note that the actual steps will depend on your system and
environment.):
1. Install utility commands on your host
* openssl
* efitools
* sbsigntool
Install the required tools on your host
2. Create signing keys and key database files on your host
for PK::
* openssl
* efitools
* sbsigntool
$ openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_PK/ \
Create signing keys and the key database on your host:
The platform key
.. code-block:: bash
openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_PK/ \
-keyout PK.key -out PK.crt -nodes -days 365
$ cert-to-efi-sig-list -g 11111111-2222-3333-4444-123456789abc \
cert-to-efi-sig-list -g 11111111-2222-3333-4444-123456789abc \
PK.crt PK.esl;
$ sign-efi-sig-list -c PK.crt -k PK.key PK PK.esl PK.auth
sign-efi-sig-list -c PK.crt -k PK.key PK PK.esl PK.auth
for KEK::
The key exchange keys
$ openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_KEK/ \
.. code-block:: bash
openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_KEK/ \
-keyout KEK.key -out KEK.crt -nodes -days 365
$ cert-to-efi-sig-list -g 11111111-2222-3333-4444-123456789abc \
cert-to-efi-sig-list -g 11111111-2222-3333-4444-123456789abc \
KEK.crt KEK.esl
$ sign-efi-sig-list -c PK.crt -k PK.key KEK KEK.esl KEK.auth
sign-efi-sig-list -c PK.crt -k PK.key KEK KEK.esl KEK.auth
for db::
The whitelist database
.. code-block:: bash
$ openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_db/ \
-keyout db.key -out db.crt -nodes -days 365
@@ -148,31 +158,35 @@ and environment.):
db.crt db.esl
$ sign-efi-sig-list -c KEK.crt -k KEK.key db db.esl db.auth
Copy \*.auth to media, say mmc, that is accessible from U-Boot.
Copy the \*.auth files to media, say mmc, that is accessible from U-Boot.
3. Sign an image with one key in "db" on your host::
Sign an image with one of the keys in "db" on your host
$ sbsign --key db.key --cert db.crt helloworld.efi
.. code-block:: bash
4. Install keys on your board::
sbsign --key db.key --cert db.crt helloworld.efi
==> fatload mmc 0:1 <tmpaddr> PK.auth
==> setenv -e -nv -bs -rt -at -i <tmpaddr>,$filesize PK
==> fatload mmc 0:1 <tmpaddr> KEK.auth
==> setenv -e -nv -bs -rt -at -i <tmpaddr>,$filesize KEK
==> fatload mmc 0:1 <tmpaddr> db.auth
==> setenv -e -nv -bs -rt -at -i <tmpaddr>,$filesize db
Now in U-Boot install the keys on your board::
5. Set up boot parameters on your board::
fatload mmc 0:1 <tmpaddr> PK.auth
setenv -e -nv -bs -rt -at -i <tmpaddr>,$filesize PK
fatload mmc 0:1 <tmpaddr> KEK.auth
setenv -e -nv -bs -rt -at -i <tmpaddr>,$filesize KEK
fatload mmc 0:1 <tmpaddr> db.auth
setenv -e -nv -bs -rt -at -i <tmpaddr>,$filesize db
==> efidebug boot add 1 HELLO mmc 0:1 /helloworld.efi.signed ""
Set up boot parameters on your board::
Then your board runs that image from Boot manager (See below).
efidebug boot add 1 HELLO mmc 0:1 /helloworld.efi.signed ""
Now your board can run the signed image via the boot manager (see below).
You can also try this sequence by running Pytest, test_efi_secboot,
on sandbox::
on the sandbox
$ cd <U-Boot source directory>
$ pytest.py test/py/tests/test_efi_secboot/test_signed.py --bd sandbox
.. code-block:: bash
cd <U-Boot source directory>
pytest.py test/py/tests/test_efi_secboot/test_signed.py --bd sandbox
Executing the boot manager
~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -11,6 +11,7 @@
#include <common.h>
#include <part_efi.h>
#include <efi_api.h>
#include <image.h>
#include <pe.h>
static inline int guidcmp(const void *g1, const void *g2)
@@ -47,6 +48,13 @@ static inline void *guidcpy(void *dst, const void *src)
/* Root node */
extern efi_handle_t efi_root;
/* EFI system partition */
extern struct efi_system_partition {
enum if_type if_type;
int devnum;
u8 part;
} efi_system_partition;
int __efi_entry_check(void);
int __efi_exit_check(void);
const char *__efi_nesting(void);
@@ -695,9 +703,6 @@ void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data);
unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data);
efi_status_t efi_bootmgr_load(efi_handle_t *handle);
#ifdef CONFIG_EFI_SECURE_BOOT
#include <image.h>
/**
* efi_image_regions - A list of memory regions
*
@@ -767,7 +772,6 @@ bool efi_secure_boot_enabled(void);
bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp,
WIN_CERTIFICATE **auth, size_t *auth_len);
#endif /* CONFIG_EFI_SECURE_BOOT */
#else /* CONFIG_IS_ENABLED(EFI_LOADER) */

View File

@@ -51,13 +51,22 @@ struct block_drvr {
#define PART_TYPE_LEN 32
#define MAX_SEARCH_PARTITIONS 64
#define PART_BOOTABLE ((int)BIT(0))
#define PART_EFI_SYSTEM_PARTITION ((int)BIT(1))
typedef struct disk_partition {
lbaint_t start; /* # of first block in partition */
lbaint_t size; /* number of blocks in partition */
ulong blksz; /* block size in bytes */
uchar name[PART_NAME_LEN]; /* partition name */
uchar type[PART_TYPE_LEN]; /* string type description */
int bootable; /* Active/Bootable flag is set */
/*
* The bootable is a bitmask with the following fields:
*
* PART_BOOTABLE the MBR bootable flag is set
* PART_EFI_SYSTEM_PARTITION the partition is an EFI system partition
*/
int bootable;
#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
char uuid[UUID_STR_LEN + 1]; /* filesystem UUID as string, if exists */
#endif

View File

@@ -13,6 +13,8 @@
#include <part.h>
#include <malloc.h>
struct efi_system_partition efi_system_partition;
const efi_guid_t efi_block_io_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
/**
@@ -418,6 +420,24 @@ static efi_status_t efi_disk_add_dev(
diskobj->ops.media = &diskobj->media;
if (disk)
*disk = diskobj;
/* Store first EFI system partition */
if (part && !efi_system_partition.if_type) {
int r;
disk_partition_t info;
r = part_get_info(desc, part, &info);
if (r)
return EFI_DEVICE_ERROR;
if (info.bootable & PART_EFI_SYSTEM_PARTITION) {
efi_system_partition.if_type = desc->if_type;
efi_system_partition.devnum = desc->devnum;
efi_system_partition.part = part;
EFI_PRINT("EFI system partition: %s %d:%d\n",
blk_get_if_type_name(desc->if_type),
desc->devnum, part);
}
}
return EFI_SUCCESS;
}

View File

@@ -43,7 +43,8 @@ def efi_boot_env(request, u_boot_config):
HELLO_PATH = u_boot_config.build_dir + '/lib/efi_loader/helloworld.efi'
try:
non_root = tool_is_in_path('udisksctl')
mnt_point = u_boot_config.persistent_data_dir + '/mnt_efisecure'
check_call('mkdir -p {}'.format(mnt_point), shell=True)
# create a disk/partition
check_call('dd if=/dev/zero of=%s bs=1MiB count=%d'
@@ -57,25 +58,11 @@ def efi_boot_env(request, u_boot_config):
check_call('dd if=%s.tmp of=%s bs=1MiB seek=1 count=%d conv=notrunc'
% (image_path, image_path, 1), shell=True)
check_call('rm %s.tmp' % image_path, shell=True)
if non_root:
out_data = check_output('udisksctl loop-setup -f %s -o %d'
% (image_path, 1048576), shell=True).decode()
m = re.search('(?<= as )(.*)\.', out_data)
loop_dev = m.group(1)
# print 'loop device is: %s' % loop_dev
out_data = check_output('udisksctl info -b %s'
% loop_dev, shell=True).decode()
m = re.search('MountPoints:[ \t]+(.*)', out_data)
mnt_point = m.group(1)
else:
loop_dev = check_output('sudo losetup -o 1MiB --sizelimit %dMiB --show -f %s | tr -d "\n"'
% (part_size, image_path), shell=True).decode()
mnt_point = '/mnt'
check_output('sudo mount -t %s -o umask=000 %s %s'
% (fs_type, loop_dev, mnt_point), shell=True)
# print 'mount point is: %s' % mnt_point
# suffix
# *.key: RSA private key in PEM
# *.crt: X509 certificate (self-signed) in PEM
@@ -134,11 +121,6 @@ def efi_boot_env(request, u_boot_config):
% (mnt_point, EFITOOLS_PATH, EFITOOLS_PATH),
shell=True)
if non_root:
check_call('udisksctl unmount -b %s' % loop_dev, shell=True)
# not needed
# check_call('udisksctl loop-delete -b %s' % loop_dev, shell=True)
else:
check_call('sudo umount %s' % loop_dev, shell=True)
check_call('sudo losetup -d %s' % loop_dev, shell=True)