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

[edk2-devel] [PATCH v3 0/6] SEV Encrypted Boot for Ovmf -- pull #1175

Merged
merged 6 commits into from Dec 14, 2020

Conversation

lersek
Copy link
Member

@lersek lersek commented Dec 4, 2020

Msgid: 20201130202819.3910-1-jejb@linux.ibm.com
https://edk2.groups.io/g/devel/message/68087
https://www.redhat.com/archives/edk2-devel-archive/2020-November/msg01247.html

v3:

- More grub and boot stripping (I think I got everything out, but
  there may be something that strayed in the boot panic resolution).
- grub.sh tidy up with tabs->spaces.
- Move the reset vector GUIDisation patch to the front so it can be
  applied independently
- Update the .dsc and .fdf files for variable policy

v2:

- Strip more out of AmdSev image (networking, secure boot, smm)
- give sev reset block a generic table guid and use it for boot secret area
- separate secret patches and make grub script more robust
- Add copyrights and fix formatting issues

v1:

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3077

This patch series is modelled on the structure of the Bhyve patches
for Ovmf, since it does somewhat similar things.  This patch series
creates a separate build for an AmdSev OVMF.fd that does nothing
except combine with grub and boot straight through the internal grub
to try to mount an encrypted volume.

Concept: SEV Secure Encrypted Images
====================================

The SEV patches in Linux and OVMF allow for the booting of SEV VMs in
an encrypted state, but don't really show how this could be done with
an encrypted image.  Since the key used to decrypt the image must be
maintained within the SEV encryption envelope, encrypted QCOW is not
an option because the key would then have to be known to QEMU which is
outside the encryption envelope.  The proposal here is that an
encrypted image should be a QCOW image consisting of two partitions,
the normal unencrypted EFI partition (Identifying it as an OVMF
bootable image) and a luks encrypted root partition.  The kernel would
be inside the encrypted root in the /boot directory.  The secret
injected securely through QEMU is extracted by OVMF and passed to grub
which uses it to mount the encrypted root and boot the kernel
normally.  The creator of the secret bundle must be satisfied with the
SEV attestation before the secret is constructed.  Unfortunately, the
SEV attestation can only be on the first QEMU firmware volume and
nothing else, so this patch series builds grub itself into a firmware
volume and places it inside OVMF so that the entire boot system can be
attested.  In a normal OVMF KVM system, the variable store is on the
second flash volume (which is read/write).  Unfortunately, this
mutable configuration provided by the variables is outside the
attestation envelope and can significantly alter the boot path,
possibly leading to secret leak, so encrypted image boot should only
be done with the OVMF.fd that combines both the code and variables.
the OVMF.fd is constructed so that it becomes impossible to interrupt
the boot sequence after attestation and the system will either boot
the image or fail. The boot sequence runs the grub.efi embedded in the
OVMF firmware volume so the encrypted image owner knows their own
version of grub is the only one that will boot before injecting the
secret.  Note this boot path actually ignores the unencrypted EFI
partition.  However, as part of this design, the encrypted image may be
booted by a standard OVMF KVM boot and in that case, the user will
have to type the encryption password.  This standard boot will be
insecure but it might be used by the constructor of the encrypted
images on their own private laptop, for instance.  The standard boot
path will use the unencrypted EFI partition.

Patches Required Outside of OVMF
================================

There is a patch set to grub which allows it to extract the SEV secret
area from the configuration table and use the secret as a password to
do a luks crypto mount of root (this is the sevsecret grub module):

https://lists.gnu.org/archive/html/grub-devel/2020-11/msg00078.html

There is also a patch to qemu which allows it to search through the
OVMF.fd and find the SEV secret area which is now described inside the
Reset Vector using the existing SEV_ES reset block.  This area is the
place QEMU will inject the encrypted SEV secret bundle.

Security of the System
======================

Since Grub is now part of the attested OVMF.fd bundle, the VM owner
knows absolutely that it will proceed straight to partition decryption
inside the attested code and boot the kernel off the encrypted
partition.  Even if a different QCOW image is substituted, the boot
will fail without revealing the secret because the system is designed
to fail hard in that case and because the secret is always contained
within the encrypted envelope it should be impossible for the cloud
operator to obtain it even if they can pause the boot and examine the
machine memory.

Putting it All Together
=======================

This is somewhat hard.  You must first understand how to boot a QEMU
system so as to have the VM pause after firmware loading (-S option)
and use the qmp port to request an attestation.  Only if the
attestation corresponds to the expected sha256sum of OVMF.fd should
the secret bundle be constructed and injected using qmp.  The tools
for constructing the secret bundle are in

https://github.com/AMDESE/sev-tool/

James

---

James Bottomley (6):
  OvmfPkg/ResetVector: convert SEV-ES Reset Block structure to be GUIDed
  OvmfPkg/Amdsev: Base commit to build encrypted boot specific OVMF
  OvmfPkg/AmdSev: add Grub Firmware Volume Package
  OvmfPkg: create a SEV secret area in the AmdSev memfd
  OvmfPkg/AmdSev: assign and protect the Sev Secret area
  OvmfPkg/AmdSev: Expose the Sev Secret area using a configuration table

 OvmfPkg/OvmfPkg.dec                           |    8 +
 OvmfPkg/AmdSev/AmdSevX64.dsc                  |  844 ++++++++++
 OvmfPkg/AmdSev/AmdSevX64.fdf                  |  456 +++++
 OvmfPkg/AmdSev/Grub/Grub.inf                  |   39 +
 OvmfPkg/AmdSev/SecretDxe/SecretDxe.inf        |   37 +
 OvmfPkg/AmdSev/SecretPei/SecretPei.inf        |   35 +
 .../PlatformBootManagerLibGrub.inf            |   71 +
 OvmfPkg/ResetVector/ResetVector.inf           |    4 +
 OvmfPkg/Include/Guid/SevLaunchSecret.h        |   28 +
 .../PlatformBootManagerLibGrub/BdsPlatform.h  |  175 ++
 OvmfPkg/AmdSev/SecretDxe/SecretDxe.c          |   26 +
 OvmfPkg/AmdSev/SecretPei/SecretPei.c          |   25 +
 .../PlatformBootManagerLibGrub/BdsPlatform.c  | 1482 +++++++++++++++++
 .../PlatformBootManagerLibGrub/PlatformData.c |  214 +++
 OvmfPkg/AmdSev/Grub/.gitignore                |    1 +
 OvmfPkg/AmdSev/Grub/grub.cfg                  |   46 +
 OvmfPkg/AmdSev/Grub/grub.sh                   |   93 ++
 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm  |   70 +-
 OvmfPkg/ResetVector/ResetVector.nasmb         |    2 +
 19 files changed, 3645 insertions(+), 11 deletions(-)
 create mode 100644 OvmfPkg/AmdSev/AmdSevX64.dsc
 create mode 100644 OvmfPkg/AmdSev/AmdSevX64.fdf
 create mode 100644 OvmfPkg/AmdSev/Grub/Grub.inf
 create mode 100644 OvmfPkg/AmdSev/SecretDxe/SecretDxe.inf
 create mode 100644 OvmfPkg/AmdSev/SecretPei/SecretPei.inf
 create mode 100644 OvmfPkg/Library/PlatformBootManagerLibGrub/PlatformBootManagerLibGrub.inf
 create mode 100644 OvmfPkg/Include/Guid/SevLaunchSecret.h
 create mode 100644 OvmfPkg/Library/PlatformBootManagerLibGrub/BdsPlatform.h
 create mode 100644 OvmfPkg/AmdSev/SecretDxe/SecretDxe.c
 create mode 100644 OvmfPkg/AmdSev/SecretPei/SecretPei.c
 create mode 100644 OvmfPkg/Library/PlatformBootManagerLibGrub/BdsPlatform.c
 create mode 100644 OvmfPkg/Library/PlatformBootManagerLibGrub/PlatformData.c
 create mode 100644 OvmfPkg/AmdSev/Grub/.gitignore
 create mode 100644 OvmfPkg/AmdSev/Grub/grub.cfg
 create mode 100644 OvmfPkg/AmdSev/Grub/grub.sh

@lersek lersek added the push Auto push patch series in PR if all checks pass label Dec 4, 2020
@mergify
Copy link

mergify bot commented Dec 4, 2020

PR can not be merged due to an Ubuntu GCC5 failure. Please resolve and resubmit

@mergify
Copy link

mergify bot commented Dec 4, 2020

PR can not be merged due to a Windows VS2019 failure. Please resolve and resubmit

@lersek
Copy link
Member Author

lersek commented Dec 14, 2020

This PR is waiting for #1224 to be merged first.

James Bottomley added 6 commits December 14, 2020 20:23
Convert the current ES reset block structure to an extensible guid
based structure by appending a header and length, which allow for
multiple guid based data packets to be inserted.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3077
Signed-off-by: James Bottomley <jejb@linux.ibm.com>
Message-Id: <20201130202819.3910-2-jejb@linux.ibm.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
This commit represents the file copied from OvmfPkgX64 with minor
changes to change the build name.

This package will form the basis for adding Sev specific features.
Since everything must go into a single rom file for attestation, the
separated build of code and variables is eliminated.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3077
Signed-off-by: James Bottomley <jejb@linux.ibm.com>
Message-Id: <20201130202819.3910-3-jejb@linux.ibm.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
This is used to package up the grub bootloader into a firmware volume
where it can be executed as a shell like the UEFI Shell.  Grub itself
is built as a minimal entity into a Fv and then added as a boot
option.  By default the UEFI shell isn't built but for debugging
purposes it can be enabled and will then be presented as a boot option
(This should never be allowed for secure boot in an external data
centre but may be useful for local debugging).  Finally all other boot
options except grub and possibly the shell are stripped and the boot
timeout forced to 0 so the system will not enter a setup menu and will
only boot to grub.  This is done by copying the
Library/PlatformBootManagerLib into Library/PlatformBootManagerLibGrub
and then customizing it.

Boot failure is fatal to try to prevent secret theft.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3077
Signed-off-by: James Bottomley <jejb@linux.ibm.com>
Message-Id: <20201130202819.3910-4-jejb@linux.ibm.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
[lersek@redhat.com: replace local variable initialization with assignment]
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
[lersek@redhat.com: squash 'OvmfPkg: add "gGrubFileGuid=Grub" to
 GuidCheck.IgnoreDuplicates', reviewed stand-alone by Phil (msgid
 <e6eae551-8563-ccfb-5547-7a97da6d46e5@redhat.com>) and Ard (msgid
 <10aeda37-def6-d9a4-6e02-4c66c1492f57@arm.com>)]
SEV needs an area to place an injected secret where OVMF can find it
and pass it up as a ConfigurationTable.  This patch implements the
area itself as an addition to the SEV enhanced reset vector table using
an additional guid (4c2eb361-7d9b-4cc3-8081-127c90d3d294).

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3077
Signed-off-by: James Bottomley <jejb@linux.ibm.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Message-Id: <20201130202819.3910-5-jejb@linux.ibm.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
[lersek@redhat.com: fix typo in "ResetVectorVtf0.asm" comments]
Create a one page secret area in the MEMFD and reserve the area with a
boot time HOB.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3077
Signed-off-by: James Bottomley <jejb@linux.ibm.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Message-Id: <20201130202819.3910-6-jejb@linux.ibm.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
[lersek@redhat.com: s/protect/reserve/g in the commit message, at Ard's
 and James's suggestion]
Now that the secret area is protected by a boot time HOB, extract its
location details into a configuration table referenced by
gSevLaunchSecretGuid so the boot loader or OS can locate it before a
call to ExitBootServices().

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3077
Signed-off-by: James Bottomley <jejb@linux.ibm.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Message-Id: <20201130202819.3910-7-jejb@linux.ibm.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
[lersek@redhat.com: fix indentation of InstallConfigurationTable() args]
@mergify mergify bot merged commit 01726b6 into tianocore:master Dec 14, 2020
@lersek lersek deleted the james_v3_encr_img_boot_pull branch December 14, 2020 20:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
push Auto push patch series in PR if all checks pass
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant