mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-24 21:34:08 +03:00
boot: Fix device path unaligned access
This commit is contained in:
parent
515581d66a
commit
71c628d426
@ -25,15 +25,14 @@ EFI_STATUS disk_get_part_uuid(EFI_HANDLE *handle, char16_t uuid[static 37]) {
|
||||
if (DevicePathSubType(dp) != MEDIA_HARDDRIVE_DP)
|
||||
continue;
|
||||
|
||||
HARDDRIVE_DEVICE_PATH *hd = (HARDDRIVE_DEVICE_PATH *) dp;
|
||||
if (hd->SignatureType != SIGNATURE_TYPE_GUID)
|
||||
/* The HD device path may be misaligned. */
|
||||
HARDDRIVE_DEVICE_PATH hd;
|
||||
memcpy(&hd, dp, MIN(sizeof(hd), (size_t) DevicePathNodeLength(dp)));
|
||||
|
||||
if (hd.SignatureType != SIGNATURE_TYPE_GUID)
|
||||
continue;
|
||||
|
||||
/* Use memcpy in case the device path node is misaligned. */
|
||||
EFI_GUID sig;
|
||||
memcpy(&sig, hd->Signature, sizeof(hd->Signature));
|
||||
|
||||
GuidToString(uuid, &sig);
|
||||
GuidToString(uuid, (EFI_GUID *) &hd.Signature);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -757,12 +757,12 @@ EFI_STATUS make_file_device_path(EFI_HANDLE device, const char16_t *file, EFI_DE
|
||||
*ret_dp = xmalloc(dp_size + file_size + SIZE_OF_FILEPATH_DEVICE_PATH + END_DEVICE_PATH_LENGTH);
|
||||
dp = mempcpy(*ret_dp, dp, dp_size);
|
||||
|
||||
/* Replace end node with file media device path. */
|
||||
FILEPATH_DEVICE_PATH *file_dp = (FILEPATH_DEVICE_PATH *) dp;
|
||||
file_dp->Header.Type = MEDIA_DEVICE_PATH;
|
||||
file_dp->Header.SubType = MEDIA_FILEPATH_DP;
|
||||
memcpy(&file_dp->PathName, file, file_size);
|
||||
SetDevicePathNodeLength(&file_dp->Header, SIZE_OF_FILEPATH_DEVICE_PATH + file_size);
|
||||
/* Replace end node with file media device path. Use memcpy() in case dp is unaligned (if accessed as
|
||||
* FILEPATH_DEVICE_PATH). */
|
||||
dp->Type = MEDIA_DEVICE_PATH;
|
||||
dp->SubType = MEDIA_FILEPATH_DP;
|
||||
memcpy((uint8_t *) dp + offsetof(FILEPATH_DEVICE_PATH, PathName), file, file_size);
|
||||
SetDevicePathNodeLength(dp, offsetof(FILEPATH_DEVICE_PATH, PathName) + file_size);
|
||||
|
||||
dp = NextDevicePathNode(dp);
|
||||
SetDevicePathEndNode(dp);
|
||||
|
@ -12,33 +12,29 @@ union GptHeaderBuffer {
|
||||
uint8_t space[CONST_ALIGN_TO(sizeof(EFI_PARTITION_TABLE_HEADER), 512)];
|
||||
};
|
||||
|
||||
static EFI_DEVICE_PATH *path_chop(EFI_DEVICE_PATH *path, EFI_DEVICE_PATH *node) {
|
||||
static EFI_DEVICE_PATH *path_replace_hd(
|
||||
const EFI_DEVICE_PATH *path,
|
||||
const EFI_DEVICE_PATH *node,
|
||||
const HARDDRIVE_DEVICE_PATH *new_node) {
|
||||
|
||||
/* Create a new device path as a copy of path, while chopping off the remainder starting at the given
|
||||
* node. If new_node is provided, it is appended at the end of the new path. */
|
||||
|
||||
assert(path);
|
||||
assert(node);
|
||||
|
||||
UINTN len = (uint8_t *) node - (uint8_t *) path;
|
||||
EFI_DEVICE_PATH *chopped = xmalloc(len + END_DEVICE_PATH_LENGTH);
|
||||
size_t len = (uint8_t *) node - (uint8_t *) path, new_node_len = 0;
|
||||
if (new_node)
|
||||
new_node_len = DevicePathNodeLength(&new_node->Header);
|
||||
|
||||
memcpy(chopped, path, len);
|
||||
SetDevicePathEndNode((EFI_DEVICE_PATH *) ((uint8_t *) chopped + len));
|
||||
EFI_DEVICE_PATH *ret = xmalloc(len + new_node_len + END_DEVICE_PATH_LENGTH);
|
||||
EFI_DEVICE_PATH *end = mempcpy(ret, path, len);
|
||||
|
||||
return chopped;
|
||||
}
|
||||
if (new_node)
|
||||
end = mempcpy(end, new_node, new_node_len);
|
||||
|
||||
static EFI_DEVICE_PATH *path_dup(const EFI_DEVICE_PATH *dp) {
|
||||
assert(dp);
|
||||
|
||||
const EFI_DEVICE_PATH *node = dp;
|
||||
size_t size = 0;
|
||||
while (!IsDevicePathEnd(node)) {
|
||||
size += DevicePathNodeLength(node);
|
||||
node = NextDevicePathNode(node);
|
||||
}
|
||||
size += DevicePathNodeLength(node);
|
||||
|
||||
EFI_DEVICE_PATH *dup = xmalloc(size);
|
||||
memcpy(dup, dp, size);
|
||||
return dup;
|
||||
SetDevicePathEndNode(end);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool verify_gpt(union GptHeaderBuffer *gpt_header_buffer, EFI_LBA lba_expected) {
|
||||
@ -149,13 +145,24 @@ static EFI_STATUS try_gpt(
|
||||
if (end < start) /* Bogus? */
|
||||
continue;
|
||||
|
||||
ret_hd->PartitionNumber = i + 1;
|
||||
ret_hd->PartitionStart = start;
|
||||
ret_hd->PartitionSize = end - start + 1;
|
||||
ret_hd->MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
|
||||
ret_hd->SignatureType = SIGNATURE_TYPE_GUID;
|
||||
*ret_hd = (HARDDRIVE_DEVICE_PATH) {
|
||||
.Header = {
|
||||
.Type = MEDIA_DEVICE_PATH,
|
||||
.SubType = MEDIA_HARDDRIVE_DP,
|
||||
},
|
||||
.PartitionNumber = i + 1,
|
||||
.PartitionStart = start,
|
||||
.PartitionSize = end - start + 1,
|
||||
.MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER,
|
||||
.SignatureType = SIGNATURE_TYPE_GUID,
|
||||
};
|
||||
memcpy(ret_hd->Signature, &entry->UniquePartitionGUID, sizeof(ret_hd->Signature));
|
||||
|
||||
/* HARDDRIVE_DEVICE_PATH has padding, which at least OVMF does not like. */
|
||||
SetDevicePathNodeLength(
|
||||
&ret_hd->Header,
|
||||
offsetof(HARDDRIVE_DEVICE_PATH, SignatureType) + sizeof(ret_hd->SignatureType));
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
@ -192,7 +199,7 @@ static EFI_STATUS find_device(EFI_HANDLE *device, EFI_DEVICE_PATH **ret_device_p
|
||||
|
||||
/* Chop off the partition part, leaving us with the full path to the disk itself. */
|
||||
_cleanup_free_ EFI_DEVICE_PATH *disk_path = NULL;
|
||||
EFI_DEVICE_PATH *p = disk_path = path_chop(partition_path, part_node);
|
||||
EFI_DEVICE_PATH *p = disk_path = path_replace_hd(partition_path, part_node, NULL);
|
||||
|
||||
EFI_HANDLE disk_handle;
|
||||
EFI_BLOCK_IO_PROTOCOL *block_io;
|
||||
@ -214,7 +221,6 @@ static EFI_STATUS find_device(EFI_HANDLE *device, EFI_DEVICE_PATH **ret_device_p
|
||||
|
||||
/* Try several copies of the GPT header, in case one is corrupted */
|
||||
EFI_LBA backup_lba = 0;
|
||||
HARDDRIVE_DEVICE_PATH hd = *((HARDDRIVE_DEVICE_PATH *) part_node);
|
||||
for (UINTN nr = 0; nr < 3; nr++) {
|
||||
EFI_LBA lba;
|
||||
|
||||
@ -230,6 +236,7 @@ static EFI_STATUS find_device(EFI_HANDLE *device, EFI_DEVICE_PATH **ret_device_p
|
||||
else
|
||||
continue;
|
||||
|
||||
HARDDRIVE_DEVICE_PATH hd;
|
||||
err = try_gpt(
|
||||
block_io, lba,
|
||||
nr == 0 ? &backup_lba : NULL, /* Only get backup LBA location from first GPT header. */
|
||||
@ -243,9 +250,7 @@ static EFI_STATUS find_device(EFI_HANDLE *device, EFI_DEVICE_PATH **ret_device_p
|
||||
}
|
||||
|
||||
/* Patch in the data we found */
|
||||
EFI_DEVICE_PATH *xboot_path = path_dup(partition_path);
|
||||
memcpy((uint8_t *) xboot_path + ((uint8_t *) part_node - (uint8_t *) partition_path), &hd, sizeof(hd));
|
||||
*ret_device_path = xboot_path;
|
||||
*ret_device_path = path_replace_hd(partition_path, part_node, &hd);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user