efi_loader: correct EFI_BLOCK_IO_PROTOCOL.Media.LastBlock

The field Media.LastBlock of the EFI_BLOCK_IO_PROTOCOL.Media was filled
incorrectly both for block devices as well as for partitions.

The field must be filled with the index of the last logical block (LBA):

* block devices: device size minus 1
* partitions: partition size minus 1

Reported-by: Alexander von Gluck IV <kallisti5@unixzen.com>
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
This commit is contained in:
Heinrich Schuchardt 2021-01-23 06:52:21 +01:00
parent 2cfb68fd83
commit 8d0949b3ed

View File

@ -343,7 +343,7 @@ static int efi_fs_exists(struct blk_desc *desc, int part)
* @if_typename: interface name for block device
* @desc: internal block device
* @dev_index: device index for block device
* @offset: offset into disk for simple partitions
* @part_info: partition info
* @part: partition
* @disk: pointer to receive the created handle
* Return: disk object
@ -354,7 +354,7 @@ static efi_status_t efi_disk_add_dev(
const char *if_typename,
struct blk_desc *desc,
int dev_index,
lbaint_t offset,
struct disk_partition *part_info,
unsigned int part,
struct efi_disk_obj **disk)
{
@ -374,7 +374,7 @@ static efi_status_t efi_disk_add_dev(
efi_add_handle(&diskobj->header);
/* Fill in object data */
if (part) {
if (part_info) {
struct efi_device_path *node = efi_dp_part_node(desc, part);
struct efi_handler *handler;
void *protocol_interface;
@ -396,8 +396,12 @@ static efi_status_t efi_disk_add_dev(
diskobj->dp = efi_dp_append_node(dp_parent, node);
efi_free_pool(node);
diskobj->offset = part_info->start;
diskobj->media.last_block = part_info->size - 1;
} else {
diskobj->dp = efi_dp_from_part(desc, part);
diskobj->offset = 0;
diskobj->media.last_block = desc->lba - 1;
}
diskobj->part = part;
@ -432,7 +436,6 @@ static efi_status_t efi_disk_add_dev(
diskobj->ops = block_io_disk_template;
diskobj->ifname = if_typename;
diskobj->dev_index = dev_index;
diskobj->offset = offset;
diskobj->desc = desc;
/* Fill in EFI IO Media info (for read/write callbacks) */
@ -445,13 +448,21 @@ static efi_status_t efi_disk_add_dev(
diskobj->media.media_id = 1;
diskobj->media.block_size = desc->blksz;
diskobj->media.io_align = desc->blksz;
diskobj->media.last_block = desc->lba - offset;
if (part)
diskobj->media.logical_partition = 1;
diskobj->ops.media = &diskobj->media;
if (disk)
*disk = diskobj;
EFI_PRINT("BlockIO: part %u, present %d, logical %d, removable %d"
", offset " LBAF ", last_block %llu\n",
diskobj->part,
diskobj->media.media_present,
diskobj->media.logical_partition,
diskobj->media.removable_media,
diskobj->offset,
diskobj->media.last_block);
/* Store first EFI system partition */
if (part && !efi_system_partition.if_type) {
int r;
@ -493,7 +504,6 @@ int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc,
{
int disks = 0;
char devname[32] = { 0 }; /* dp->str is u16[32] long */
struct disk_partition info;
int part;
struct efi_device_path *dp = NULL;
efi_status_t ret;
@ -506,12 +516,14 @@ int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc,
/* Add devices for each partition */
for (part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
struct disk_partition info;
if (part_get_info(desc, part, &info))
continue;
snprintf(devname, sizeof(devname), "%s:%d", pdevname,
part);
ret = efi_disk_add_dev(parent, dp, if_typename, desc, diskid,
info.start, part, NULL);
&info, part, NULL);
if (ret != EFI_SUCCESS) {
log_err("Adding partition %s failed\n", pdevname);
continue;
@ -553,7 +565,7 @@ efi_status_t efi_disk_register(void)
/* Add block device for the full device */
log_info("Scanning disk %s...\n", dev->name);
ret = efi_disk_add_dev(NULL, NULL, if_typename,
desc, desc->devnum, 0, 0, &disk);
desc, desc->devnum, NULL, 0, &disk);
if (ret == EFI_NOT_READY) {
log_notice("Disk %s not ready\n", dev->name);
continue;
@ -599,7 +611,7 @@ efi_status_t efi_disk_register(void)
/* Add block device for the full device */
ret = efi_disk_add_dev(NULL, NULL, if_typename, desc,
i, 0, 0, &disk);
i, NULL, 0, &disk);
if (ret == EFI_NOT_READY) {
log_notice("Disk %s not ready\n", devname);
continue;