Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for AMD SKINIT to slaunch #17

Merged
merged 4 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions grub-core/Makefile.core.def
Original file line number Diff line number Diff line change
Expand Up @@ -1822,6 +1822,7 @@ module = {
x86 = loader/i386/txt/txt.c;
x86 = loader/i386/txt/acmod.c;
x86 = loader/i386/txt/verify.c;
x86 = loader/i386/skinit.c;
enable = x86;
};

Expand Down
6 changes: 6 additions & 0 deletions grub-core/lib/i386/relocator32.S
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ VARIABLE(grub_relocator32_edx)
cmpl $SLP_INTEL_TXT, %edi
je LOCAL(intel_txt)

cmpl $SLP_AMD_SKINIT, %edi
je LOCAL(amd_skinit)

.byte 0xea
VARIABLE(grub_relocator32_eip)
.long 0
Expand All @@ -123,6 +126,9 @@ VARIABLE(grub_relocator32_eip)
LOCAL(intel_txt):
getsec

LOCAL(amd_skinit):
skinit

/* GDT. Copied from loader/i386/linux.c. */
.p2align 4
LOCAL(gdt):
Expand Down
157 changes: 157 additions & 0 deletions grub-core/loader/i386/skinit.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
*
* 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/>.
*/

#include <grub/cpu/relocator.h>
#include <grub/dl.h>
#include <grub/i386/skinit.h>
#include <grub/i386/tpm.h>
#include <grub/mm.h>
#include <grub/slr_table.h>
#include <grub/types.h>

#define SLRT_SIZE GRUB_PAGE_SIZE

/* Offset to entry point. */
#define SLB_ENTRY(slb) ((const grub_uint16_t *) (slb))[0]
/* Amount of data actually measured for DRTM. */
#define SLB_MEASURED(slb) ((const grub_uint16_t *) (slb))[1]
/* Offset to structure with extra info. */
#define SLB_INFO(slb) ((const grub_uint16_t *) (slb))[2]
/* Offset to area for passing data to SKL. */
#define SLB_PARAM(slb) ((const grub_uint16_t *) (slb))[3]

int
grub_skinit_is_slb (const void *slb_base, grub_uint32_t slb_size)
{
const grub_uint8_t skl_uuid[16] = {
0x78, 0xf1, 0x26, 0x8e, 0x04, 0x92, 0x11, 0xe9,
0x83, 0x2a, 0xc8, 0x5b, 0x76, 0xc4, 0xcc, 0x02,
};
/* We need space after SLB to pass SLRT to it. */
const grub_ssize_t max_size = GRUB_SKINIT_SLB_SIZE - SLRT_SIZE;

const grub_uint8_t *uuid;

if (slb_size > max_size)
{
grub_dprintf ("slaunch", "SLB is too large: %d > %d\n",
slb_size, max_size);
return 0;
}

if (SLB_MEASURED (slb_base) > slb_size)
{
grub_dprintf ("slaunch", "SLB measured size is too large: %d > %d\n",
SLB_MEASURED (slb_base), slb_size);
return 0;
}

if (SLB_ENTRY (slb_base) >= SLB_MEASURED (slb_base))
{
grub_dprintf ("slaunch", "SLB entry is not measured: %d >= %d\n",
SLB_ENTRY (slb_base), SLB_MEASURED (slb_base));
return 0;
}

if (SLB_INFO (slb_base) > SLB_MEASURED (slb_base) - sizeof(skl_uuid))
{
grub_dprintf ("slaunch", "SLB info is not measured: %d > %d\n",
SLB_INFO (slb_base),
SLB_MEASURED (slb_base) - sizeof(skl_uuid));
return 0;
}

if (SLB_PARAM (slb_base) > max_size)
{
grub_dprintf ("slaunch", "SLB bootloader data offset is too large: %d > %d\n",
SLB_PARAM (slb_base), max_size);
return 0;
}

uuid = (const grub_uint8_t *) slb_base + SLB_INFO (slb_base);
if (grub_memcmp (uuid, skl_uuid, sizeof(skl_uuid)) != 0)
{
grub_dprintf ("slaunch", "SLB has unexpected UUID\n");
return 0;
}

return 1;
}

grub_err_t
grub_skinit_boot_prepare (struct grub_relocator *rel,
struct grub_slaunch_params *slparams)
{
grub_uint32_t *apic = (grub_uint32_t *)0xfee00300ULL;
const void *slb = grub_slaunch_module ();
grub_relocator_chunk_t ch;
grub_err_t err;
void *dce_mem;

if (slb == NULL)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "SLB module is missing");

err = grub_relocator_alloc_chunk_align (rel, &ch, 0x1000000,
0xffffffff - GRUB_SLAUNCH_TPM_EVT_LOG_SIZE,
GRUB_SLAUNCH_TPM_EVT_LOG_SIZE, GRUB_PAGE_SIZE,
GRUB_RELOCATOR_PREFERENCE_NONE, 1);

if (err != GRUB_ERR_NONE)
return grub_error (err, "cannot alloc memory for TPM event log");

slparams->tpm_evt_log_base = get_physical_target_address (ch);
slparams->tpm_evt_log_size = GRUB_SLAUNCH_TPM_EVT_LOG_SIZE;
grub_memset (get_virtual_current_address (ch), 0, slparams->tpm_evt_log_size);

grub_dprintf ("slaunch", "tpm_evt_log_base = %lx, tpm_evt_log_size = %x\n",
(unsigned long) slparams->tpm_evt_log_base,
(unsigned) slparams->tpm_evt_log_size);

/* Contrary to the TXT, on AMD we do not have vendor-provided blobs in
* reserved memory, we are using normal RAM */
err = grub_relocator_alloc_chunk_align (rel, &ch, 0,
0xffffffff - GRUB_SKINIT_SLB_SIZE,
GRUB_SKINIT_SLB_SIZE,
GRUB_SKINIT_SLB_ALIGN,
GRUB_RELOCATOR_PREFERENCE_LOW, 1);

if (err != GRUB_ERR_NONE)
return grub_error (err, "cannot alloc memory for SLB");

slparams->dce_base = get_physical_target_address (ch);
slparams->dce_size = SLB_MEASURED (slb);

dce_mem = get_virtual_current_address (ch);
grub_memcpy (dce_mem, slb, slparams->dce_size);

slparams->slr_table_base = slparams->dce_base + SLB_PARAM (slb);
slparams->slr_table_size = SLRT_SIZE;
slparams->slr_table_mem = (grub_uint8_t *) dce_mem + SLB_PARAM (slb);
grub_memset (slparams->slr_table_mem, 0, SLRT_SIZE);

grub_slaunch_init_slrt_storage (GRUB_SLR_AMD_SKINIT);

grub_dprintf ("slaunch", "broadcasting INIT\r\n");
*apic = 0x000c0500; // INIT, all excluding self
grub_dprintf ("slaunch", "grub_tpm_relinquish_locality\r\n");
grub_tpm_relinquish_locality (0);

grub_dprintf ("slaunch", "Invoke SKINIT\r\n");

return GRUB_ERR_NONE;
}
53 changes: 43 additions & 10 deletions grub-core/loader/i386/slaunch.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <grub/i386/cpuid.h>
#include <grub/i386/msr.h>
#include <grub/i386/mmio.h>
#include <grub/i386/skinit.h>
#include <grub/i386/slaunch.h>
#include <grub/i386/tpm.h>
#include <grub/i386/txt.h>
Expand Down Expand Up @@ -77,8 +78,12 @@ grub_slaunch_init_slrt_storage (int arch)
/* Setup DCE and DLME information. */
slr_dl_info_staging.hdr.tag = GRUB_SLR_ENTRY_DL_INFO;
slr_dl_info_staging.hdr.size = sizeof(struct grub_slr_entry_dl_info);
slr_dl_info_staging.bl_context.bootloader = GRUB_SLR_BOOTLOADER_GRUB;
slr_dl_info_staging.bl_context.context = slparams.boot_params_addr;
slr_dl_info_staging.dce_base = slparams.dce_base;
slr_dl_info_staging.dce_size = slparams.dce_size;
slr_dl_info_staging.dlme_base = slparams.mle_start;
slr_dl_info_staging.dlme_size = slparams.mle_size;
slr_dl_info_staging.dlme_entry = mle_header->entry_point;
krystian-hebel marked this conversation as resolved.
Show resolved Hide resolved

slr_log_info_staging.hdr.tag = GRUB_SLR_ENTRY_LOG_INFO;
Expand Down Expand Up @@ -152,7 +157,8 @@ grub_cmd_slaunch (grub_command_t cmd __attribute__ ((unused)),
char *argv[] __attribute__ ((unused)))
{
grub_uint32_t manufacturer[3];
grub_uint32_t eax;
grub_uint32_t eax, ebx, ecx, edx;
grub_uint64_t msr_value;
grub_err_t err;

if (!grub_cpu_is_cpuid_supported ())
Expand All @@ -174,6 +180,19 @@ grub_cmd_slaunch (grub_command_t cmd __attribute__ ((unused)),

slp = SLP_INTEL_TXT;
}
else if (!grub_memcmp (manufacturer, "AuthenticAMD", 12))
{
grub_cpuid (GRUB_AMD_CPUID_FEATURES, eax, ebx, ecx, edx);
if (! (ecx & GRUB_AMD_CPUID_FEATURES_ECX_SVM) )
return grub_error (GRUB_ERR_BAD_DEVICE, N_("CPU does not support AMD SVM"));

/* Check whether SVM feature is disabled in BIOS */
msr_value = grub_rdmsr (GRUB_MSR_AMD64_VM_CR);
if (msr_value & GRUB_MSR_SVM_VM_CR_SVM_DISABLE)
return grub_error (GRUB_ERR_BAD_DEVICE, N_("BIOS has AMD SVM disabled"));

slp = SLP_AMD_SKINIT;
}
else
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("CPU is unsupported"));

Expand All @@ -186,14 +205,15 @@ grub_cmd_slaunch_module (grub_command_t cmd __attribute__ ((unused)),
{
grub_file_t file;
grub_ssize_t size;
void *new_module = NULL;

if (!argc)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));

if (slp == SLP_NONE)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("secure launch not enabled"));

if (slp > SLP_INTEL_TXT)
if (slp > SLP_AMD_SKINIT)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
N_("unknown secure launch platform type: %d"), slp);

Expand All @@ -212,12 +232,12 @@ grub_cmd_slaunch_module (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}

slaunch_module = grub_malloc (size);
new_module = grub_malloc (size);

if (slaunch_module == NULL)
if (new_module == NULL)
goto fail;

if (grub_file_read (file, slaunch_module, size) != size)
if (grub_file_read (file, new_module, size) != size)
{
if (grub_errno == GRUB_ERR_NONE)
grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file: %s"),
Expand All @@ -227,31 +247,40 @@ grub_cmd_slaunch_module (grub_command_t cmd __attribute__ ((unused)),

if (slp == SLP_INTEL_TXT)
krystian-hebel marked this conversation as resolved.
Show resolved Hide resolved
{
if (!grub_txt_is_sinit_acmod (slaunch_module, size))
if (!grub_txt_is_sinit_acmod (new_module, size))
{
grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("it does not look like SINIT ACM"));
goto fail;
}

if (!grub_txt_acmod_match_platform (slaunch_module))
if (!grub_txt_acmod_match_platform (new_module))
{
grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("SINIT ACM does not match platform"));
goto fail;
}
}
else if (slp == SLP_AMD_SKINIT)
{
if (!grub_skinit_is_slb (new_module, size))
{
grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("it does not look like SLB"));
goto fail;
}
}

grub_file_close (file);

grub_free (slaunch_module);
slaunch_module = new_module;

return GRUB_ERR_NONE;

fail:
grub_error_push ();

grub_free (slaunch_module);
grub_free (new_module);
grub_file_close (file);

slaunch_module = NULL;

grub_error_pop ();

return grub_errno;
Expand All @@ -269,6 +298,10 @@ grub_cmd_slaunch_state (grub_command_t cmd __attribute__ ((unused)),
grub_printf ("Secure launcher: Intel TXT\n");
grub_txt_state_show ();
}
else if (slp == SLP_AMD_SKINIT)
{
grub_printf ("Secure launcher: AMD SKINIT\n");
}
else
return grub_error (GRUB_ERR_BAD_ARGUMENT,
N_("Unknown secure launcher platform type: %d\n"), slp);
Expand Down
12 changes: 9 additions & 3 deletions grub-core/loader/multiboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include <grub/memory.h>
#include <grub/i18n.h>
#if defined (__i386__) || defined (__x86_64__)
#include <grub/i386/skinit.h>
#include <grub/i386/slaunch.h>
#include <grub/i386/txt.h>
#endif
Expand Down Expand Up @@ -176,6 +177,11 @@ normal_boot (struct grub_relocator *rel, struct grub_relocator32_state state)
state.ecx = slparams->dce_size;
state.edx = 0;
}
else if (state.edi == SLP_AMD_SKINIT)
{
state.eax = slparams->dce_base;
state.edi = SLP_AMD_SKINIT;
}

grub_relocator32_boot (rel, state, 0);
}
Expand Down Expand Up @@ -206,10 +212,10 @@ grub_multiboot_boot (void)
return err;

#ifdef GRUB_USE_MULTIBOOT2
if (grub_slaunch_platform_type () == SLP_INTEL_TXT)
if (grub_slaunch_platform_type () != SLP_NONE)
{
err = grub_multiboot2_prepare_slaunch_txt (state.MULTIBOOT_MBI_REGISTER,
mbi_size);
err = grub_multiboot2_prepare_slaunch (state.MULTIBOOT_MBI_REGISTER,
mbi_size);
if (err)
return err;
}
Expand Down
8 changes: 4 additions & 4 deletions grub-core/loader/multiboot_elfxx.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
(long) mld->align, mld->preference, load_size,
mld->avoid_efi_boot_services);

if (grub_slaunch_platform_type () == SLP_INTEL_TXT)
if (grub_slaunch_platform_type () != SLP_NONE)
{
#ifndef GRUB_USE_MULTIBOOT2
return grub_error (GRUB_ERR_BAD_OS, "Only multiboot2 supported for slaunch");
Expand Down Expand Up @@ -158,7 +158,7 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
grub_dprintf ("multiboot_loader", "load_base_addr=0x%lx, source=0x%lx\n",
(long) mld->load_base_addr, (long) source);

if (grub_slaunch_platform_type () == SLP_INTEL_TXT)
if (grub_slaunch_platform_type () != SLP_NONE)
{
#ifndef GRUB_USE_MULTIBOOT2
return grub_error (GRUB_ERR_BAD_OS, "Only multiboot2 supported for slaunch");
Expand Down Expand Up @@ -189,7 +189,7 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
{
mld->load_base_addr = mld->link_base_addr;
/* TODO: support non-relocatable */
if (grub_slaunch_platform_type () == SLP_INTEL_TXT)
if (grub_slaunch_platform_type () != SLP_NONE)
return grub_error (GRUB_ERR_BAD_OS, "Non-relocatable ELF not supported with slaunch");
}

Expand Down Expand Up @@ -247,7 +247,7 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
}
}

if (grub_slaunch_platform_type () == SLP_INTEL_TXT)
if (grub_slaunch_platform_type () != SLP_NONE)
{
slparams->mle_header_offset = 0xffffffff;

Expand Down
Loading