It turns out checking from userspace is not 100% reliable to figure out whether the firmware had TPM2 support enabled or not. For example with EDK2 arm64, the default upstream build config bundles TPM2 support with SecureBoot support, so if the latter is disabled, TPM2 is also unavailable. But still, the ACPI TPM2 table is created just as if it was enabled. So, /sys/firmware/acpi/tables/TPM2 exists and looks correct but there are no measurements, neither the firmware nor the loader/stub can do them, and /sys/kernel/security/tpm0/binary_bios_measurements does not exist. So, userspace cannot really tell what was going on in UEFI mode. The loader can use the apposite UEFI protocol to check, which is a more definitive answer. Export the bitmask with the list of active banks as-is. If it's not 0, then in userspace we can be sure a working TPM2 was available in UEFI mode. systemd-boot and systemd-stub v258 (current main) set this variable and userspace portion consumes it to be able to tell what was available in the firmware context. Signed-off-by: Luca Boccassi <luca.boccassi@gmail.com> Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
162 lines
4.8 KiB
C
162 lines
4.8 KiB
C
/*
|
|
* GRUB -- GRand Unified Bootloader
|
|
* Copyright (C) 2023 Free Software Foundation, Inc.
|
|
*
|
|
* GRUB is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* GRUB is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Implementation of the Boot Loader Interface.
|
|
*/
|
|
|
|
#include <grub/charset.h>
|
|
#include <grub/efi/api.h>
|
|
#include <grub/efi/disk.h>
|
|
#include <grub/efi/efi.h>
|
|
#include <grub/err.h>
|
|
#include <grub/extcmd.h>
|
|
#include <grub/gpt_partition.h>
|
|
#include <grub/misc.h>
|
|
#include <grub/mm.h>
|
|
#include <grub/partition.h>
|
|
#include <grub/tpm.h>
|
|
#include <grub/types.h>
|
|
|
|
GRUB_MOD_LICENSE ("GPLv3+");
|
|
|
|
#define MODNAME "bli"
|
|
|
|
static const grub_guid_t bli_vendor_guid = GRUB_EFI_VENDOR_BOOT_LOADER_INTERFACE_GUID;
|
|
|
|
static grub_err_t
|
|
get_part_uuid (const char *device_name, char **part_uuid)
|
|
{
|
|
grub_device_t device;
|
|
grub_err_t status = GRUB_ERR_NONE;
|
|
grub_disk_t disk = NULL;
|
|
struct grub_gpt_partentry entry;
|
|
|
|
device = grub_device_open (device_name);
|
|
if (device == NULL)
|
|
return grub_error (grub_errno, N_("cannot open device: %s"), device_name);
|
|
|
|
if (device->disk == NULL)
|
|
{
|
|
grub_dprintf ("bli", "%s is not a disk device, partuuid skipped\n", device_name);
|
|
*part_uuid = NULL;
|
|
grub_device_close (device);
|
|
return GRUB_ERR_NONE;
|
|
}
|
|
|
|
if (device->disk->partition == NULL)
|
|
{
|
|
grub_dprintf ("bli", "%s has no partition, partuuid skipped\n", device_name);
|
|
*part_uuid = NULL;
|
|
grub_device_close (device);
|
|
return GRUB_ERR_NONE;
|
|
}
|
|
|
|
disk = grub_disk_open (device->disk->name);
|
|
if (disk == NULL)
|
|
{
|
|
status = grub_error (grub_errno, N_("cannot open disk: %s"), device_name);
|
|
grub_device_close (device);
|
|
return status;
|
|
}
|
|
|
|
if (grub_strcmp (device->disk->partition->partmap->name, "gpt") != 0)
|
|
{
|
|
status = grub_error (GRUB_ERR_BAD_PART_TABLE,
|
|
N_("this is not a GPT partition table: %s"), device_name);
|
|
goto fail;
|
|
}
|
|
|
|
if (grub_disk_read (disk, device->disk->partition->offset,
|
|
device->disk->partition->index, sizeof (entry), &entry) != GRUB_ERR_NONE)
|
|
{
|
|
status = grub_error (grub_errno, N_("read error: %s"), device_name);
|
|
goto fail;
|
|
}
|
|
|
|
*part_uuid = grub_xasprintf ("%pG", &entry.guid);
|
|
if (*part_uuid == NULL)
|
|
status = grub_errno;
|
|
|
|
fail:
|
|
grub_disk_close (disk);
|
|
grub_device_close (device);
|
|
|
|
return status;
|
|
}
|
|
|
|
static grub_err_t
|
|
set_loader_device_part_uuid (void)
|
|
{
|
|
grub_efi_loaded_image_t *image;
|
|
char *device_name;
|
|
grub_err_t status = GRUB_ERR_NONE;
|
|
char *part_uuid = NULL;
|
|
|
|
image = grub_efi_get_loaded_image (grub_efi_image_handle);
|
|
if (image == NULL)
|
|
return grub_error (GRUB_ERR_BAD_DEVICE, N_("unable to find boot device"));
|
|
|
|
device_name = grub_efidisk_get_device_name (image->device_handle);
|
|
if (device_name == NULL)
|
|
return grub_error (GRUB_ERR_BAD_DEVICE, N_("unable to find boot device"));
|
|
|
|
status = get_part_uuid (device_name, &part_uuid);
|
|
|
|
if (status == GRUB_ERR_NONE && part_uuid)
|
|
status = grub_efi_set_variable_to_string ("LoaderDevicePartUUID", &bli_vendor_guid, part_uuid,
|
|
GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
|
GRUB_EFI_VARIABLE_RUNTIME_ACCESS);
|
|
else
|
|
grub_error (status, N_("unable to determine partition UUID of boot device"));
|
|
|
|
grub_free (part_uuid);
|
|
grub_free (device_name);
|
|
return status;
|
|
}
|
|
|
|
static grub_err_t
|
|
set_loader_active_pcr_banks (void)
|
|
{
|
|
grub_efi_uint32_t active_pcr_banks;
|
|
char *active_pcr_banks_str;
|
|
grub_err_t status;
|
|
|
|
active_pcr_banks = grub_tpm2_active_pcr_banks();
|
|
active_pcr_banks_str = grub_xasprintf ("0x%08x", active_pcr_banks);
|
|
if (active_pcr_banks_str == NULL)
|
|
return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate active PCR banks string"));
|
|
|
|
status = grub_efi_set_variable_to_string ("LoaderTpm2ActivePcrBanks",
|
|
&bli_vendor_guid,
|
|
active_pcr_banks_str,
|
|
GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
|
GRUB_EFI_VARIABLE_RUNTIME_ACCESS);
|
|
grub_free (active_pcr_banks_str);
|
|
return status;
|
|
}
|
|
|
|
GRUB_MOD_INIT (bli)
|
|
{
|
|
grub_efi_set_variable_to_string ("LoaderInfo", &bli_vendor_guid, PACKAGE_STRING,
|
|
GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
|
GRUB_EFI_VARIABLE_RUNTIME_ACCESS);
|
|
set_loader_device_part_uuid ();
|
|
set_loader_active_pcr_banks ();
|
|
/* No error here is critical, other than being logged */
|
|
grub_print_error ();
|
|
}
|