mirror of
https://git.proxmox.com/git/efi-boot-shim
synced 2025-06-14 21:27:53 +00:00

Add parameter checking to parse_sbat(). Set end pointer to be sbat_base + sbat_size - 1. We directly dereference the end pointer but this is technically outside of our sbat_base buffer range. Remove current and end while loops that account for extra CRLF or LF characters before and after the .sbat section. We will rely on automated tooling to verify the .sbat section is sane. Remove the overwriting of *(end - 1) with '\0'. This behavior causes a segfault in the unit test. parse_sbat_entry() expects a very specific pattern "_,_,_,_,_,_\n" for every entry and uses strchrnul() to process each individual field. When *(end - 1)='\0' is present, it short-circuits the final \n and causes the final get_sbat_field() to return NULL, thereby setting current = NULL. Eventually parse_sbat attempts to access current in the do-while condition and the segfault happens. Signed-off-by: Chris Co <chrco@microsoft.com>
121 lines
2.6 KiB
C
121 lines
2.6 KiB
C
// SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
/*
|
|
* sbat.c - parse SBAT data from the .sbat section data
|
|
*/
|
|
|
|
#include "shim.h"
|
|
|
|
CHAR8 *
|
|
get_sbat_field(CHAR8 *current, CHAR8 *end, const CHAR8 **field, char delim)
|
|
{
|
|
CHAR8 *offset;
|
|
|
|
if (!field || !current || !end || current >= end)
|
|
return NULL;
|
|
|
|
offset = strchrnula(current, delim);
|
|
*field = current;
|
|
|
|
if (!*offset)
|
|
return NULL;
|
|
|
|
*offset = '\0';
|
|
return offset + 1;
|
|
}
|
|
|
|
EFI_STATUS
|
|
parse_sbat_entry(CHAR8 **current, CHAR8 *end, struct sbat_entry **sbat_entry)
|
|
{
|
|
struct sbat_entry *entry = NULL;
|
|
|
|
entry = AllocateZeroPool(sizeof(*entry));
|
|
if (!entry)
|
|
return EFI_OUT_OF_RESOURCES;
|
|
|
|
*current = get_sbat_field(*current, end, &entry->component_name, ',');
|
|
if (!entry->component_name)
|
|
goto error;
|
|
|
|
*current = get_sbat_field(*current, end, &entry->component_generation,
|
|
',');
|
|
if (!entry->component_generation)
|
|
goto error;
|
|
|
|
*current = get_sbat_field(*current, end, &entry->vendor_name, ',');
|
|
if (!entry->vendor_name)
|
|
goto error;
|
|
|
|
*current =
|
|
get_sbat_field(*current, end, &entry->vendor_package_name, ',');
|
|
if (!entry->vendor_package_name)
|
|
goto error;
|
|
|
|
*current = get_sbat_field(*current, end, &entry->vendor_version, ',');
|
|
if (!entry->vendor_version)
|
|
goto error;
|
|
|
|
*current = get_sbat_field(*current, end, &entry->vendor_url, '\n');
|
|
if (!entry->vendor_url)
|
|
goto error;
|
|
|
|
*sbat_entry = entry;
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
error:
|
|
FreePool(entry);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
EFI_STATUS
|
|
parse_sbat(char *sbat_base, size_t sbat_size, struct sbat *sbat)
|
|
{
|
|
CHAR8 *current = (CHAR8 *) sbat_base;
|
|
CHAR8 *end = (CHAR8 *) sbat_base + sbat_size - 1;
|
|
EFI_STATUS efi_status = EFI_SUCCESS;
|
|
struct sbat_entry *entry;
|
|
struct sbat_entry **entries;
|
|
unsigned int i;
|
|
|
|
if (!sbat_base || !sbat || sbat_size == 0)
|
|
return EFI_INVALID_PARAMETER;
|
|
|
|
if (current == end)
|
|
return EFI_INVALID_PARAMETER;
|
|
|
|
do {
|
|
entry = NULL;
|
|
efi_status = parse_sbat_entry(¤t, end, &entry);
|
|
if (EFI_ERROR(efi_status))
|
|
goto error;
|
|
|
|
if (end < current) {
|
|
efi_status = EFI_INVALID_PARAMETER;
|
|
goto error;
|
|
}
|
|
|
|
if (entry) {
|
|
entries = ReallocatePool(
|
|
sbat->entries, sbat->size * sizeof(entry),
|
|
(sbat->size + 1) * sizeof(entry));
|
|
if (!entries) {
|
|
efi_status = EFI_OUT_OF_RESOURCES;
|
|
goto error;
|
|
}
|
|
|
|
sbat->entries = entries;
|
|
sbat->entries[sbat->size] = entry;
|
|
sbat->size++;
|
|
}
|
|
} while (entry && *current != '\0');
|
|
|
|
return efi_status;
|
|
error:
|
|
perror(L"Failed to parse SBAT data: %r\n", efi_status);
|
|
for (i = 0; i < sbat->size; i++)
|
|
FreePool(sbat->entries[i]);
|
|
return efi_status;
|
|
}
|
|
|
|
// vim:fenc=utf-8:tw=75:noet
|